GetFEM  5.5
getfem_interpolation.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2001-2026 Yves Renard, Julien Pommier
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program. If not, see https://www.gnu.org/licenses/.
19 
20  As a special exception, you may use this file as it is a part of a free
21  software library without restriction. Specifically, if other files
22  instantiate templates or use macros or inline functions from this file,
23  or you compile this file and link it with other files to produce an
24  executable, this file does not by itself cause the resulting executable
25  to be covered by the GNU Lesser General Public License. This exception
26  does not however invalidate any other reasons why the executable file
27  might be covered by the GNU Lesser General Public License.
28 
29 ===========================================================================*/
30 
31 /**@file getfem_interpolation.h
32  @author Yves Renard <Yves.Renard@insa-lyon.fr>
33  @author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
34  @date October 15, 2001.
35  @brief Interpolation of fields from a mesh_fem onto another.
36 */
37 
38 #ifndef GETFEM_INTERPOLATION_H__
39 #define GETFEM_INTERPOLATION_H__
40 
41 #include "getfem_mesh_fem.h"
42 #include "bgeot_torus.h"
43 #include "dal_tree_sorted.h"
44 #include "getfem_im_data.h"
45 #include "getfem_torus.h"
46 
47 namespace getfem {
48 
49  /* ********************************************************************* */
50  /* */
51  /* I. Distribution of a set of points on a mesh. */
52  /* */
53  /* ********************************************************************* */
54 
55  class mesh_trans_inv : public bgeot::geotrans_inv {
56 
57  protected :
58  const mesh &msh;
59  std::vector<std::set<size_type> > pts_in_cvx;
60  std::vector<base_node> ref_coords;
61  // optional renumbering of point indices to point ids
62  std::map<size_type,size_type> ids;
63 
64  public :
65 
66  size_type nb_points_on_convex(size_type i) const
67  { return pts_in_cvx[i].size(); }
68  void points_on_convex(size_type i, std::vector<size_type> &itab) const;
69  size_type point_on_convex(size_type cv, size_type i) const;
70  const std::vector<base_node> &reference_coords() const { return ref_coords; }
71 
72  void add_point_with_id(base_node n, size_type id)
73  { size_type ipt = add_point(n); ids[ipt] = id; }
74  size_type id_of_point(size_type ipt) const;
75  const mesh &linked_mesh() const { return msh; }
76 
77  /* extrapolation = 0 : Only the points inside the mesh are distributed.
78  * extrapolation = 1 : Try to extrapolate the exterior points near the
79  * boundary.
80  * extrapolation = 2 : Extrapolate all the exterior points. Could be
81  * expensive.
82  *
83  * if rg_source is provided only the corresponding part of the mesh is
84  * taken into account and extrapolation is done with respect to the
85  * boundary of the specified region. rg_source must contain only convexes.
86  */
87  void distribute(int extrapolation = 0,
88  mesh_region rg_source=mesh_region::all_convexes());
89  mesh_trans_inv(const mesh &m, double EPS_ = 1E-12)
90  : bgeot::geotrans_inv(EPS_), msh(m) {}
91  };
92 
93 
94  /* ********************************************************************* */
95  /* */
96  /* II. Interpolation of functions. */
97  /* */
98  /* ********************************************************************* */
99 
100 
101  template <typename VECT, typename F, typename M>
102  inline void interpolation_function__(const mesh_fem &mf, VECT &V,
103  F &f, const dal::bit_vector &dofs,
104  const M &, gmm::abstract_null_type) {
105  size_type Q = mf.get_qdim();
106  GMM_ASSERT1(gmm::vect_size(V) == mf.nb_basic_dof() && Q == 1,
107  "Dof vector has not the right size");
108  for (dal::bv_visitor i(dofs); !i.finished(); ++i)
109  V[i] = f(mf.point_of_basic_dof(i));
110  }
111 
112  template <typename VECT, typename F, typename M>
113  inline void interpolation_function__(const mesh_fem &mf, VECT &V,
114  F &f, const dal::bit_vector &dofs,
115  const M &v, gmm::abstract_vector) {
116  size_type N = gmm::vect_size(v), Q = mf.get_qdim();
117  GMM_ASSERT1(gmm::vect_size(V) == mf.nb_basic_dof()*N/Q,
118  "Dof vector has not the right size");
119  for (dal::bv_visitor i(dofs); !i.finished(); ++i)
120  if (i % Q == 0)
121  gmm::copy(f(mf.point_of_basic_dof(i)),
122  gmm::sub_vector(V, gmm::sub_interval(i*N/Q, N)));
123  }
124 
125  template <typename VECT, typename F, typename M>
126  inline void interpolation_function__(const mesh_fem &mf, VECT &V,
127  F &f, const dal::bit_vector &dofs,
128  const M &mm, gmm::abstract_matrix) {
129  // typedef typename gmm::linalg_traits<VECT>::value_type T;
130  size_type Nr = gmm::mat_nrows(mm), Nc = gmm::mat_ncols(mm), N = Nr*Nc;
131  size_type Q = mf.get_qdim();
132  base_matrix m(Nr, Nc);
133  GMM_ASSERT1(gmm::vect_size(V) == mf.nb_basic_dof()*N/Q,
134  "Dof vector has not the right size");
135  for (dal::bv_visitor i(dofs); !i.finished(); ++i)
136  if (i % Q == 0) {
137  gmm::copy(f(mf.point_of_basic_dof(i)), m);
138  for (size_type j = 0; j < Nc; ++j)
139  gmm::copy(gmm::mat_col(m, j),
140  gmm::sub_vector(V, gmm::sub_interval(i*N/Q+j*Nr, Nr)));
141  }
142 
143  }
144 
145  template <typename VECT, typename F, typename M>
146  inline void interpolation_function_(const mesh_fem &mf, VECT &V,
147  F &f, const dal::bit_vector &dofs,
148  const M &m) {
149  interpolation_function__(mf, V, f, dofs, m,
150  typename gmm::linalg_traits<M>::linalg_type());
151  }
152 
153 #if GETFEM_PARA_LEVEL > 0
154  template <typename T>
155  void take_one_op(void *a, void *b, int *len, MPI_Datatype *) {
156  T aa = *((T*)a);
157  return aa ? aa : *((T*)b);
158  }
159 
160  template <typename T>
161  inline MPI_Op mpi_take_one_op(T) {
162  static bool isinit = false;
163  static MPI_Op op;
164  if (!isinit) {
165  MPI_Op_create(take_one_op<T>, true, &op);
166  isinit = true;
167  }
168  return op;
169  }
170 #endif
171 
172  // TODO : verify that rhs is a lagrange fem
173  /**
174  @brief interpolation of a function f on mf_target.
175  - mf_target must be of lagrange type.
176  - mf_target's qdim should be equal to the size of the return value of f,
177  or equal to 1
178  - V should have the right size
179  CAUTION: with the parallized version (GETFEM_PARA_LEVEL >= 2) the
180  resulting vector V is distributed.
181  */
182  template <typename VECT, typename F>
183  void interpolation_function(mesh_fem &mf_target, const VECT &VV, F &f,
185  typedef typename gmm::linalg_traits<VECT>::value_type T;
186  size_type qqdimt = gmm::vect_size(VV) / mf_target.nb_dof();
187  std::vector<T> V(mf_target.nb_basic_dof()*qqdimt);
188  mf_target.linked_mesh().intersect_with_mpi_region(rg);
189  dal::bit_vector dofs = mf_target.basic_dof_on_region(rg);
190  if (dofs.card() > 0)
191  interpolation_function_(mf_target, V, f, dofs,
192  f(mf_target.point_of_basic_dof(dofs.first())));
193 
194  if (mf_target.is_reduced()) {
195  for (size_type k = 0; k < qqdimt; ++k)
196  gmm::mult(mf_target.reduction_matrix(),
197  gmm::sub_vector(V,
198  gmm::sub_slice(k, mf_target.nb_basic_dof(),
199  qqdimt)),
200  gmm::sub_vector(const_cast<VECT &>(VV),
201  gmm::sub_slice(k, mf_target.nb_dof(),
202  qqdimt)));
203  }
204  else
205  gmm::copy(V, const_cast<VECT &>(VV));
206  }
207 
208  /* ********************************************************************* */
209  /* */
210  /* III. Interpolation between two meshes. */
211  /* */
212  /* ********************************************************************* */
213 
214  /* ------------------------------ Interface -----------------------------*/
215 
216  /**
217  @brief interpolation/extrapolation of (mf_source, U) on mf_target.
218  - mf_target must be of lagrange type.
219  - mf_target's qdim should be equal to mf_source qdim, or equal to 1
220  - U.size() >= mf_source.get_qdim()
221  - V.size() >= (mf_target.nb_dof() / mf_target.get_qdim())
222  * mf_source.get_qdim()
223 
224  With extrapolation = 0 a strict interpolation is done, with extrapolation = 1
225  an extrapolation of the exterior points near the boundary is done (if any)
226  and with extrapolation = 2 all exterior points are extrapolated (could be expensive).
227 
228  If both mesh_fem shared the same mesh object, a fast interpolation
229  will be used.
230 
231  If rg_source and rg_target are provided the operation is restricted to
232  these regions. rg_source must contain only convexes.
233  */
234  template<typename VECTU, typename VECTV>
235  void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target,
236  const VECTU &U, VECTV &V, int extrapolation = 0,
237  double EPS = 1E-10,
238  mesh_region rg_source=mesh_region::all_convexes(),
239  mesh_region rg_target=mesh_region::all_convexes());
240 
241  /**
242  @brief Build the interpolation matrix of mf_source on mf_target.
243  the matrix M is
244  such that (V = M*U) == interpolation(mf_source, mf_target, U, V).
245 
246  Useful for repeated interpolations.
247  For performance reasons the matrix M is recommended to be either
248  a row or a row and column matrix.
249 
250  If rg_source and rg_target are provided the operation is restricted to
251  these regions. rg_source must contain only convexes.
252  */
253  template<typename MAT>
254  void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target,
255  MAT &M, int extrapolation = 0, double EPS = 1E-10,
256  mesh_region rg_source=mesh_region::all_convexes(),
257  mesh_region rg_target=mesh_region::all_convexes());
258 
259 
260  /* --------------------------- Implementation ---------------------------*/
261 
262  /*
263  interpolation of a solution on same mesh.
264  - &mf_target.linked_mesh() == &mf_source.linked_mesh()
265  - mf_target must be of lagrange type.
266  - mf_target's qdim should be equal to mf_source qdim, or equal to 1
267  - U.size() >= mf_source.get_qdim()
268  - V.size() >= (mf_target.nb_dof() / mf_target.get_qdim())
269  * mf_source.get_qdim()
270  */
271  template<typename VECTU, typename VECTV, typename MAT>
272  void interpolation_same_mesh(const mesh_fem &mf_source,
273  const mesh_fem &mf_target,
274  const VECTU &UU, VECTV &VV,
275  MAT &MM, int version) {
276 
277  typedef typename gmm::linalg_traits<VECTU>::value_type T;
278  base_matrix G;
279  dim_type qdim = mf_source.get_qdim();
280  dim_type qqdim = dim_type(gmm::vect_size(UU)/mf_source.nb_dof());
281  std::vector<T> val(qdim);
282  std::vector<std::vector<T> > coeff;
283  std::vector<size_type> dof_source;
284  GMM_ASSERT1(qdim == mf_target.get_qdim() || mf_target.get_qdim() == 1,
285  "Attempt to interpolate a field of dimension "
286  << qdim << " on a mesh_fem whose Qdim is " <<
287  int(mf_target.get_qdim()));
288  size_type qmult = mf_source.get_qdim()/mf_target.get_qdim();
289  size_type qqdimt = qqdim * mf_source.get_qdim()/mf_target.get_qdim();
290  fem_precomp_pool fppool;
291  std::vector<size_type> dof_t_passes(mf_target.nb_basic_dof());
292  std::vector<T> U(mf_source.nb_basic_dof()*qqdim);
293  std::vector<T> V(mf_target.nb_basic_dof()*qqdimt);
294  gmm::row_matrix<gmm::rsvector<scalar_type> >
295  M(mf_target.nb_basic_dof(), mf_source.nb_basic_dof());
296 
297  if (version == 0) mf_source.extend_vector(UU, U);
298 
299  /* we should sort convexes by their fem */
300  for (dal::bv_visitor cv(mf_source.convex_index()); !cv.finished(); ++cv) {
301  bgeot::pgeometric_trans pgt=mf_source.linked_mesh().trans_of_convex(cv);
302  pfem pf_s = mf_source.fem_of_element(cv);
303  if (!mf_target.convex_index().is_in(cv))
304  continue;
305  pfem pf_t = mf_target.fem_of_element(cv);
306  size_type nbd_s = pf_s->nb_dof(cv);
307  size_type nbd_t = pf_t->nb_dof(cv);
308  mesh_fem::ind_dof_ct::const_iterator itdof;
309  size_type cvnbdof = mf_source.nb_basic_dof_of_element(cv);
310 
311  bool discontinuous_source = false;
312  for (size_type dof=0; dof < nbd_s; ++dof)
313  if (!dof_linkable(pf_s->dof_types()[dof])) {
314  discontinuous_source = true;
315  break;
316  }
317 
318  if (version == 0) {
319  coeff.resize(qqdim);
320  for (size_type qq=0; qq < qqdim; ++qq) {
321  coeff[qq].resize(cvnbdof);
322  itdof = mf_source.ind_basic_dof_of_element(cv).begin();
323  for (size_type k = 0; k < cvnbdof; ++k, ++itdof) {
324  coeff[qq][k] = U[(*itdof)*qqdim+qq];
325  }
326  }
327  }
328  if (pf_s->need_G())
329  bgeot::vectors_to_base_matrix
330  (G, mf_source.linked_mesh().points_of_convex(cv));
331 
332  GMM_ASSERT1(pf_t->target_dim() == 1,
333  "won't interpolate on a vector FEM... ");
334  pfem_precomp pfp = fppool(pf_s, pf_t->node_tab(cv));
335  fem_interpolation_context ctx(pgt,pfp,size_type(-1), G, cv,
336  short_type(-1));
337  itdof = mf_target.ind_basic_dof_of_element(cv).begin();
338  if (version != 0) {
339  const mesh_fem::ind_dof_ct &idct
340  = mf_source.ind_basic_dof_of_element(cv);
341  dof_source.assign(idct.begin(), idct.end());
342  }
343  for (size_type i = 0; i < nbd_t; ++i, itdof+=mf_target.get_qdim()) {
344  size_type dof_t = *itdof*qmult;
345  if (!discontinuous_source && dof_t_passes[*itdof] > 0) continue;
346  dof_t_passes[*itdof] += 1;
347  ctx.set_ii(i);
348  if (version == 0) {
349  for (size_type qq=0; qq < qqdim; ++qq) {
350  pf_s->interpolation(ctx, coeff[qq], val, qdim);
351  for (size_type k=0; k < qdim; ++k)
352  V[(dof_t + k)*qqdim+qq] += val[k];
353  }
354  }
355  else {
356  base_matrix Mloc(qdim, mf_source.nb_basic_dof_of_element(cv));
357  pf_s->interpolation(ctx, Mloc, qdim);
358  for (size_type k=0; k < qdim; ++k) {
359  for (size_type j=0; j < dof_source.size(); ++j) {
360  M(dof_t + k, dof_source[j]) += Mloc(k, j);
361  }
362  }
363  }
364  }
365  }
366 
367  // calculate averages for discontinuous source and continuous target
368  for (size_type i = 0; i < mf_target.nb_basic_dof(); ++i) {
369  size_type dof_t = i*qmult;
370  scalar_type passes = scalar_type(dof_t_passes[i]);
371  if (version == 0 && passes > scalar_type(0))
372  for (size_type qq=0; qq < qqdim; ++qq)
373  for (size_type k=0; k < qdim; ++k)
374  V[(dof_t + k)*qqdim+qq] /= passes;
375  else if (passes > scalar_type(0))
376  for (size_type k=0; k < qdim; ++k)
377  for (size_type j=0; j < dof_source.size(); ++j)
378  gmm::scale(gmm::mat_row(M, dof_t + k), scalar_type(1)/passes);
379  }
380 
381  if (version == 0)
382  mf_target.reduce_vector(V, VV);
383  else {
384  if (mf_target.is_reduced())
385  if (mf_source.is_reduced()) {
386  gmm::row_matrix<gmm::rsvector<scalar_type> >
387  MMM(mf_target.nb_dof(), mf_source.nb_basic_dof());
388  gmm::mult(mf_target.reduction_matrix(), M, MMM);
389  gmm::mult(MMM, mf_source.extension_matrix(), MM);
390  }
391  else
392  gmm::mult(mf_target.reduction_matrix(), M, MM);
393  else
394  if (mf_source.is_reduced())
395  gmm::mult(M, mf_source.extension_matrix(), MM);
396  else
397  gmm::copy(M, MM);
398  }
399  }
400 
401 
402  /*
403  interpolation of a solution on another mesh.
404  - mti contains the points where to interpolate.
405  - the solution should be continuous.
406  */
407  template<typename VECTU, typename VECTV, typename MAT>
408  void interpolation(const mesh_fem &mf_source,
409  mesh_trans_inv &mti,
410  const VECTU &UU, VECTV &V, MAT &MM,
411  int version, int extrapolation = 0,
412  dal::bit_vector *dof_untouched = 0,
413  mesh_region rg_source=mesh_region::all_convexes()) {
414 
415  typedef typename gmm::linalg_traits<VECTU>::value_type T;
416  const mesh &msh(mf_source.linked_mesh());
417  dim_type qdim_s = mf_source.get_qdim();
418  dim_type qqdim = dim_type(gmm::vect_size(UU)/mf_source.nb_dof());
419 
420  std::vector<T> U(mf_source.nb_basic_dof()*qqdim);
421  gmm::row_matrix<gmm::rsvector<scalar_type> > M;
422  if (version != 0) M.resize(gmm::mat_nrows(MM), mf_source.nb_basic_dof());
423 
424  if (version == 0) mf_source.extend_vector(UU, U);
425 
426  mti.distribute(extrapolation, rg_source);
427  std::vector<size_type> itab;
428  base_matrix G;
429 
430  /* interpolation */
431  dal::bit_vector points_to_do; points_to_do.add(0, mti.nb_points());
432  std::vector<T> val(qdim_s);
433  std::vector<std::vector<T> > coeff;
434  base_tensor Z;
435  std::vector<size_type> dof_source;
436 
437  for (dal::bv_visitor cv(mf_source.convex_index()); !cv.finished(); ++cv) {
438  bgeot::pgeometric_trans pgt = msh.trans_of_convex(cv);
439  mti.points_on_convex(cv, itab);
440  if (itab.size() == 0) continue;
441 
442  pfem pf_s = mf_source.fem_of_element(cv);
443  if (pf_s->need_G())
444  bgeot::vectors_to_base_matrix(G, msh.points_of_convex(cv));
445 
446  fem_interpolation_context ctx(pgt, pf_s, base_node(), G, cv,
447  short_type(-1));
448  if (version == 0) {
449  coeff.resize(qqdim);
450  size_type cvnbdof = mf_source.nb_basic_dof_of_element(cv);
451  mesh_fem::ind_dof_ct::const_iterator itdof;
452  for (size_type qq=0; qq < qqdim; ++qq) {
453  coeff[qq].resize(cvnbdof);
454  itdof = mf_source.ind_basic_dof_of_element(cv).begin();
455  for (size_type k = 0; k < cvnbdof; ++k, ++itdof) {
456  coeff[qq][k] = U[(*itdof)*qqdim+qq];
457  }
458  }
459  }
460  if (version != 0) {
461  const mesh_fem::ind_dof_ct &idct
462  = mf_source.ind_basic_dof_of_element(cv);
463  dof_source.assign(idct.begin(), idct.end());
464  }
465  for (size_type i = 0; i < itab.size(); ++i) {
466  size_type ipt = itab[i];
467  if (points_to_do.is_in(ipt)) {
468  points_to_do.sup(ipt);
469  ctx.set_xref(mti.reference_coords()[ipt]);
470  size_type dof_t = mti.id_of_point(ipt);
471  size_type pos = dof_t * qdim_s;
472  if (version == 0) {
473  for (size_type qq=0; qq < qqdim; ++qq) {
474  pf_s->interpolation(ctx, coeff[qq], val, qdim_s);
475  for (size_type k=0; k < qdim_s; ++k)
476  V[(pos + k)*qqdim+qq] = val[k];
477  }
478  // Part to be improved if one wants in option to be able to
479  // interpolate the gradient.
480  // if (PVGRAD) {
481  // base_matrix grad(mdim, qdim);
482  // pf_s->interpolation_grad(ctx,coeff,gmm::transposed(grad), qdim);
483  // std::copy(grad.begin(), grad.end(), V.begin()+dof_t*qdim*mdim);
484  // }
485  } else {
486  base_matrix Mloc(qdim_s, mf_source.nb_basic_dof_of_element(cv));
487  pf_s->interpolation(ctx, Mloc, qdim_s);
488  for (size_type k=0; k < qdim_s; ++k) {
489  for (size_type j=0; j < gmm::mat_ncols(Mloc); ++j)
490  M(pos+k, dof_source[j]) = Mloc(k,j);
491  /* does not work with col matrices
492  gmm::clear(gmm::mat_row(M, pos+k));
493  gmm::copy(gmm::mat_row(Mloc, k),
494  gmm::sub_vector(gmm::mat_row(M, pos+k), isrc));
495  */
496  }
497  }
498  }
499  }
500  }
501  if (points_to_do.card() != 0) {
502  if (dof_untouched) {
503  dof_untouched->clear();
504  for (dal::bv_visitor ipt(points_to_do); !ipt.finished(); ++ipt)
505  dof_untouched->add(mti.id_of_point(ipt));
506  }
507  else {
508  dal::bit_vector dofs_to_do;
509  for (dal::bv_visitor ipt(points_to_do); !ipt.finished(); ++ipt)
510  dofs_to_do.add(mti.id_of_point(ipt));
511  GMM_WARNING2("in interpolation (different meshes),"
512  << dofs_to_do.card() << " dof of target mesh_fem have "
513  << " been missed\nmissing dofs : " << dofs_to_do);
514  }
515  }
516 
517  if (version != 0) {
518  if (mf_source.is_reduced())
519  gmm::mult(M, mf_source.extension_matrix(), MM);
520  else
521  gmm::copy(M, MM);
522  }
523 
524  }
525 
526  template<typename VECTU, typename VECTV>
527  void interpolation(const mesh_fem &mf_source, mesh_trans_inv &mti,
528  const VECTU &U, VECTV &V, int extrapolation = 0,
529  dal::bit_vector *dof_untouched = 0,
530  mesh_region rg_source=mesh_region::all_convexes()) {
531  base_matrix M;
532  GMM_ASSERT1((gmm::vect_size(U) % mf_source.nb_dof()) == 0 &&
533  gmm::vect_size(V)!=0, "Dimension of vector mismatch");
534  interpolation(mf_source, mti, U, V, M, 0, extrapolation, dof_untouched, rg_source);
535  }
536 
537 
538 
539  /*
540  interpolation of a solution on another mesh.
541  - mf_target must be of lagrange type.
542  - the solution should be continuous..
543  */
544  template<typename VECTU, typename VECTV, typename MAT>
545  void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target,
546  const VECTU &U, VECTV &VV, MAT &MM,
547  int version, int extrapolation,
548  double EPS,
549  mesh_region rg_source=mesh_region::all_convexes(),
550  mesh_region rg_target=mesh_region::all_convexes()) {
551 
552  //Check if it is a torus mesh_fem
553  const torus_mesh_fem * pmf_torus = dynamic_cast<const torus_mesh_fem *>(&mf_target);
554  if(pmf_torus != 0){
555  interpolation_to_torus_mesh_fem(mf_source, *pmf_torus,
556  U, VV, MM, version, extrapolation, EPS, rg_source, rg_target);
557  return;
558  }
559 
560  typedef typename gmm::linalg_traits<VECTU>::value_type T;
561  dim_type qqdim = dim_type(gmm::vect_size(U)/mf_source.nb_dof());
562  size_type qqdimt = qqdim * mf_source.get_qdim()/mf_target.get_qdim();
563  std::vector<T> V(mf_target.nb_basic_dof()*qqdimt);
564  mf_target.extend_vector(VV,V);
565  gmm::row_matrix<gmm::rsvector<scalar_type> > M;
566  if (version != 0) M.resize(mf_target.nb_basic_dof(), mf_source.nb_dof());
567 
568  const mesh &msh(mf_source.linked_mesh());
569  getfem::mesh_trans_inv mti(msh, EPS);
570  size_type qdim_s = mf_source.get_qdim(), qdim_t = mf_target.get_qdim();
571  GMM_ASSERT1(qdim_s == qdim_t || qdim_t == 1,
572  "Attempt to interpolate a field of dimension "
573  << qdim_s << " on a mesh_fem whose Qdim is " << qdim_t);
574 
575  /* test if the target mesh_fem is really of Lagrange type. */
576  for (dal::bv_visitor cv(mf_target.convex_index()); !cv.finished();++cv) {
577  pfem pf_t = mf_target.fem_of_element(cv);
578  GMM_ASSERT1(pf_t->target_dim() == 1 && pf_t->is_lagrange(),
579  "Target fem not convenient for interpolation");
580  }
581  /* initialisation of the mesh_trans_inv */
582  bool is_target_torus = dynamic_cast<const torus_mesh *>(&mf_target.linked_mesh());
583  if (rg_target.id() == mesh_region::all_convexes().id()) {
584  size_type nbpts = mf_target.nb_basic_dof() / qdim_t;
585  for (size_type i = 0; i < nbpts; ++i){
586  if (is_target_torus){
587  auto p = mf_target.point_of_basic_dof(i * qdim_t);
588  p.resize(msh.dim());
589  mti.add_point(p);
590  }
591  else mti.add_point(mf_target.point_of_basic_dof(i * qdim_t));
592  }
593  }
594  else {
595  for (dal::bv_visitor_c dof(mf_target.basic_dof_on_region(rg_target));
596  !dof.finished(); ++dof)
597  if (dof % qdim_t == 0){
598  if (is_target_torus){
599  auto p = mf_target.point_of_basic_dof(dof);
600  p.resize(msh.dim());
601  mti.add_point_with_id(p, dof/qdim_t);
602  }
603  else
604  mti.add_point_with_id(mf_target.point_of_basic_dof(dof),dof/qdim_t);
605  }
606  }
607  interpolation(mf_source, mti, U, V, M, version, extrapolation, 0,rg_source);
608 
609  if (version == 0)
610  mf_target.reduce_vector(V, VV);
611  else {
612  if (mf_target.is_reduced())
613  gmm::mult(mf_target.reduction_matrix(), M, MM);
614  else
615  gmm::copy(M, MM);
616  }
617 
618  }
619 
620  /*
621  interpolation of a solution on another torus mesh.
622  - the solution should be continuous.
623  */
624  template<typename VECTU, typename VECTV, typename MAT>
625  void interpolation_to_torus_mesh_fem(const mesh_fem &mf_source, const torus_mesh_fem &mf_target,
626  const VECTU &U, VECTV &VV, MAT &MM,
627  int version, int extrapolation,
628  double EPS,
629  mesh_region rg_source=mesh_region::all_convexes(),
630  mesh_region rg_target=mesh_region::all_convexes()) {
631 
632  typedef typename gmm::linalg_traits<VECTU>::value_type T;
633  dim_type qqdim = dim_type(gmm::vect_size(U)/mf_source.nb_dof());
634  size_type qqdimt = qqdim * mf_source.get_qdim()/mf_target.get_qdim();
635  std::vector<T> V(mf_target.nb_basic_dof()*qqdimt);
636  mf_target.extend_vector(VV,V);
637  gmm::row_matrix<gmm::rsvector<scalar_type> >
638  M(mf_target.nb_basic_dof(), mf_source.nb_dof());
639 
640  const mesh &msh(mf_source.linked_mesh());
641  getfem::mesh_trans_inv mti(msh, EPS);
642  size_type qdim_s = mf_source.get_qdim(), qdim_t = mf_target.get_qdim();
643  GMM_ASSERT1(qdim_s == qdim_t || qdim_t == 1,
644  "Attempt to interpolate a field of dimension "
645  << qdim_s << " on a mesh_fem whose Qdim is " << qdim_t);
646 
647  /* test if the target mesh_fem is convenient for interpolation. */
648  for (dal::bv_visitor cv(mf_target.convex_index()); !cv.finished();++cv) {
649  pfem pf_t = mf_target.fem_of_element(cv);
650 
651  GMM_ASSERT1(pf_t->target_dim() == 1 ||
652  (mf_target.get_qdim() == mf_target.linked_mesh().dim()),
653  "Target fem not convenient for interpolation");
654  }
655  /* initialisation of the mesh_trans_inv */
656  if (rg_target.id() == mesh_region::all_convexes().id()) {
657  size_type nbpts = mf_target.nb_basic_dof() / qdim_t;
658  for (size_type i = 0; i < nbpts; ++i)
659  {
660  base_node p(msh.dim());
661  for (size_type k=0; k < msh.dim(); ++k) p[k] = mf_target.point_of_basic_dof(i * qdim_t)[k];
662  mti.add_point(p);
663  }
664  interpolation(mf_source, mti, U, V, M, version, extrapolation);
665  }
666  else {
667  for (dal::bv_visitor_c dof(mf_target.basic_dof_on_region(rg_target)); !dof.finished(); ++dof)
668  if (dof % qdim_t == 0)
669  {
670  base_node p(msh.dim());
671  for (size_type k=0; k < msh.dim(); ++k) p[k] = mf_target.point_of_basic_dof(dof)[k];
672  mti.add_point_with_id(p, dof/qdim_t);
673  }
674  interpolation(mf_source, mti, U, V, M, version, extrapolation, 0, rg_source);
675  }
676 
677  if (version == 0)
678  mf_target.reduce_vector(V, VV);
679  else {
680  if (mf_target.is_reduced())
681  gmm::mult(mf_target.reduction_matrix(), M, MM);
682  else
683  gmm::copy(M, MM);
684  }
685  }
686 
687 
688 
689  template<typename VECTU, typename VECTV>
690  void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target,
691  const VECTU &U, VECTV &V, int extrapolation,
692  double EPS,
693  mesh_region rg_source, mesh_region rg_target) {
694  base_matrix M;
695  GMM_ASSERT1((gmm::vect_size(U) % mf_source.nb_dof()) == 0
696  && (gmm::vect_size(V) % mf_target.nb_dof()) == 0
697  && gmm::vect_size(V) != 0, "Dimensions mismatch");
698  if (&mf_source.linked_mesh() == &mf_target.linked_mesh() &&
699  rg_source.id() == mesh_region::all_convexes().id() &&
700  rg_target.id() == mesh_region::all_convexes().id())
701  interpolation_same_mesh(mf_source, mf_target, U, V, M, 0);
702  else {
703  omp_distribute<VECTV> V_distributed;
704  auto partitioning_allowed = rg_source.is_partitioning_allowed();
705  rg_source.prohibit_partitioning();
707  auto &V_thrd = V_distributed.thrd_cast();
708  gmm::resize(V_thrd, V.size());
710  mf_source, mf_target, U, V_thrd, M, 0, extrapolation, EPS,
711  rg_source, rg_target);
712  )
713  for (size_type thread=0; thread != V_distributed.num_threads(); ++thread){
714  auto &V_thrd2 = V_distributed(thread);
715  for (size_type i = 0; i < V_thrd2.size(); ++i) {
716  if (gmm::abs(V_thrd2[i]) > EPS) V[i] = V_thrd2[i];
717  }
718  }
719  if (partitioning_allowed) rg_source.allow_partitioning();
720  }
721  }
722 
723  template<typename MAT>
724  void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target,
725  MAT &M, int extrapolation, double EPS,
726  mesh_region rg_source, mesh_region rg_target) {
727  GMM_ASSERT1(mf_source.nb_dof() == gmm::mat_ncols(M)
728  && (gmm::mat_nrows(M) % mf_target.nb_dof()) == 0
729  && gmm::mat_nrows(M) != 0, "Dimensions mismatch");
730  std::vector<scalar_type> U, V;
731  if (&mf_source.linked_mesh() == &mf_target.linked_mesh() &&
732  rg_source.id() == mesh_region::all_convexes().id() &&
733  rg_target.id() ==mesh_region::all_convexes().id())
734  interpolation_same_mesh(mf_source, mf_target, U, V, M, 1);
735  else
736  interpolation(mf_source, mf_target, U, V, M, 1, extrapolation, EPS,
737  rg_source, rg_target);
738  }
739 
740 
741  /**Interpolate mesh_fem data to im_data.
742  The qdim of mesh_fem must be equal to im_data nb_tensor_elem.
743  Both im_data and mesh_fem must reside in the same mesh.
744  Only convexes defined with both mesh_fem and im_data will be interpolated.
745  The use_im_data_filter flag controls the use of the filtered region of
746  im_data (default) or the use the full mesh.
747  */
748  template <typename VECT>
749  void interpolation_to_im_data(const mesh_fem &mf_source, const im_data &im_target,
750  const VECT &nodal_data, VECT &int_pt_data,
751  bool use_im_data_filter = true) {
752  // typedef typename gmm::linalg_traits<const VECT>::value_type T;
753 
754  dim_type qdim = mf_source.get_qdim();
755  size_type nb_dof = mf_source.nb_dof();
756  size_type nb_basic_dof = mf_source.nb_basic_dof();
757  size_type nodal_data_size = gmm::vect_size(nodal_data);
758  dim_type data_qdim = nodal_data_size / nb_dof;
759 
760  GMM_ASSERT1(data_qdim * mf_source.nb_dof() == nodal_data_size,
761  "Incompatible size of mesh fem " << mf_source.nb_dof() * data_qdim <<
762  " with the data " << nodal_data_size);
763 
764  GMM_ASSERT1(qdim * data_qdim == im_target.nb_tensor_elem(),
765  "Incompatible size of qdim for mesh_fem " << qdim
766  << " and im_data " << im_target.nb_tensor_elem());
767  GMM_ASSERT1(&mf_source.linked_mesh() == &im_target.linked_mesh(),
768  "mf_source and im_data do not share the same mesh.");
769 
770  GMM_ASSERT1(nb_dof * data_qdim == nodal_data_size,
771  "Provided nodal data size is " << nodal_data_size
772  << " but expecting vector size of " << nb_dof);
773 
774  size_type size_im_data = im_target.nb_index(use_im_data_filter)
775  * im_target.nb_tensor_elem();
776  GMM_ASSERT1(size_im_data == gmm::vect_size(int_pt_data),
777  "Provided im data size is " << gmm::vect_size(int_pt_data)
778  << " but expecting vector size of " << size_im_data);
779 
780  VECT extended_nodal_data_((nb_dof != nb_basic_dof) ? nb_basic_dof * data_qdim : 0);
781  if (nb_dof != nb_basic_dof)
782  mf_source.extend_vector(nodal_data, extended_nodal_data_);
783  const VECT &extended_nodal_data = (nb_dof == nb_basic_dof) ? nodal_data : extended_nodal_data_;
784 
785  dal::bit_vector im_data_convex_index(im_target.convex_index(use_im_data_filter));
786 
787  base_matrix G;
788  base_vector coeff;
789  bgeot::base_tensor tensor_int_point(im_target.tensor_size());
790  fem_precomp_pool fppool;
791  for (dal::bv_visitor cv(im_data_convex_index); !cv.finished(); ++cv) {
792 
793  bgeot::pgeometric_trans pgt = mf_source.linked_mesh().trans_of_convex(cv);
794  pfem pf_source = mf_source.fem_of_element(cv);
795  if (pf_source == NULL)
796  continue;
797 
798  mesh_fem::ind_dof_ct::const_iterator it_dof;
799  size_type cv_nb_dof = mf_source.nb_basic_dof_of_element(cv);
800  size_type nb_nodal_pt = cv_nb_dof / qdim;
801  coeff.resize(cv_nb_dof);
802  getfem::slice_vector_on_basic_dof_of_element(mf_source, extended_nodal_data, cv, coeff);
803 
804  const getfem::papprox_integration pim(im_target.approx_int_method_of_element(cv));
805  if (pf_source->need_G())
806  bgeot::vectors_to_base_matrix(G, *(pim->pintegration_points()));
807 
808  pfem_precomp pfp = fppool(pf_source, pim->pintegration_points());
809 
810  // interior of the convex
811  size_type nb_int_pts;
812  size_type int_pt_id = im_target.index_of_first_point(cv, short_type(-1),
813  use_im_data_filter);
814  if (int_pt_id != size_type(-1)) {
815  nb_int_pts = im_target.nb_points_of_element(cv, short_type(-1));
816  fem_interpolation_context ctx(pgt, pfp, size_type(-1), G, cv);
817  for (size_type i = 0; i < nb_int_pts; ++i, ++int_pt_id) {
818  ctx.set_ii(i);
819  ctx.pf()->interpolation(ctx, coeff, tensor_int_point.as_vector(), qdim * data_qdim);
820  im_target.set_tensor(int_pt_data, int_pt_id, tensor_int_point);
821  }
822  }
823 
824  // convex faces
825  for (short_type f=0, nb_faces=im_target.nb_faces_of_element(cv);
826  f < nb_faces; ++f) {
827  int_pt_id = im_target.index_of_first_point(cv, f, use_im_data_filter);
828  if (int_pt_id != size_type(-1)) {
829  nb_int_pts = im_target.nb_points_of_element(cv, f);
830  fem_interpolation_context ctx(pgt, pfp, size_type(-1), G, cv, f);
831  size_type i0 = pim->ind_first_point_on_face(f);
832  for (size_type i = 0; i < nb_int_pts; ++i, ++int_pt_id) {
833  ctx.set_ii(i+i0);
834  ctx.pf()->interpolation(ctx, coeff, tensor_int_point.as_vector(), qdim * data_qdim);
835  im_target.set_tensor(int_pt_data, int_pt_id, tensor_int_point);
836  }
837  }
838  }
839  }//end of convex loop
840  }
841 
842 } /* end of namespace getfem. */
843 
844 
845 #endif /* GETFEM_INTERPOLATION_H__ */
Provides mesh of torus.
void set_ii(size_type ii__)
change the current point (assuming a geotrans_precomp_ is used)
handles the geometric inversion for a given (supposedly quite large) set of points
size_type add_point(base_node p)
Add point p to the list of points.
structure passed as the argument of fem interpolation functions.
Definition: getfem_fem.h:749
handle a pool (i.e.
Definition: getfem_fem.h:716
im_data provides indexing to the integration points of a mesh im object.
const mesh & linked_mesh() const
linked mesh
void set_tensor(VECT &V1, size_type cv, size_type i, const TENSOR &T, bool use_filter=true) const
set a tensor of an integration point from a raw vector data, described by the tensor size.
size_type nb_points_of_element(size_type cv, bool use_filter=false) const
Total number of points in element cv.
size_type nb_index(bool use_filter=false) const
Total numbers of index (integration points)
short_type nb_faces_of_element(size_type cv) const
Number of (active) faces in element cv.
size_type index_of_first_point(size_type cv, short_type f=short_type(-1), bool use_filter=false) const
Returns the index of the first integration point with no filtering.
size_type nb_tensor_elem() const
sum of tensor elements, M(3,3) will have 3*3=9 elements
dal::bit_vector convex_index(bool use_filter=false) const
List of convexes.
Describe a finite element method linked to a mesh.
virtual dim_type get_qdim() const
Return the Q dimension.
virtual size_type nb_dof() const
Return the total number of degrees of freedom.
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.
const REDUCTION_MATRIX & reduction_matrix() const
Return the reduction matrix applied to the dofs.
virtual base_node point_of_basic_dof(size_type cv, size_type i) const
Return the geometrical location of a degree of freedom.
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.
bool is_reduced() const
Return true if a reduction matrix is applied to the dofs.
structure used to hold a set of convexes and/or convex faces.
void allow_partitioning()
In multithreaded part of the program makes only a partition of the region visible in the index() and ...
void prohibit_partitioning()
Disregard partitioning, which means being able to see the whole region in multithreaded code.
static mesh_region all_convexes()
provide a default value for the mesh_region parameters of assembly procedures etc.
Use this template class for any object you want to distribute to open_MP threads.
Definition: getfem_omp.h:325
a balanced tree stored in a dal::dynamic_array
Provides indexing of integration points for mesh_im.
Define the getfem::mesh_fem class.
#define GETFEM_OMP_PARALLEL(body)
Organizes a proper parallel omp section:
Definition: getfem_omp.h:482
Provides mesh and mesh fem of torus.
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1663
bool dof_linkable(pdof_description)
Says if the dof is linkable.
Definition: getfem_fem.cc:615
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:243
const pfem pf() const
get the current FEM descriptor
Definition: getfem_fem.h:781
Basic Geometric Tools.
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:72
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
GEneric Tool for Finite Element Methods.
void interpolation_function(mesh_fem &mf_target, const VECT &VV, F &f, mesh_region rg=mesh_region::all_convexes())
interpolation of a function f on mf_target.
void interpolation_to_im_data(const mesh_fem &mf_source, const im_data &im_target, const VECT &nodal_data, VECT &int_pt_data, bool use_im_data_filter=true)
Interpolate mesh_fem data to im_data.
void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target, const VECTU &U, VECTV &V, int extrapolation=0, double EPS=1E-10, mesh_region rg_source=mesh_region::all_convexes(), mesh_region rg_target=mesh_region::all_convexes())
interpolation/extrapolation of (mf_source, U) on mf_target.
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.