GetFEM  5.5
getfem_derivatives.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2002-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_derivatives.h
32  @author Yves Renard <Yves.Renard@insa-lyon.fr>,
33  @author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
34  @date June 17, 2002.
35  @brief Compute the gradient of a field on a getfem::mesh_fem.
36 */
37 #ifndef GETFEM_DERIVATIVES_H__
38 #define GETFEM_DERIVATIVES_H__
39 
40 #include "getfem_mesh_fem.h"
41 #include "getfem_interpolation.h"
42 #include "gmm/gmm_dense_qr.h"
43 
44 namespace getfem
45 {
46  /** Compute the gradient of a field on a getfem::mesh_fem.
47  @param mf the source mesh_fem.
48  @param U the source field.
49  @param mf_target should be a lagrange discontinous element
50  @param V contains on output the gradient of U, evaluated on mf_target.
51 
52  mf_target may have the same Qdim than mf, or it may
53  be a scalar mesh_fem, in which case the derivatives are stored in
54  the order: DxUx,DyUx,DzUx,DxUy,DyUy,...
55 
56  in any case, the size of V should be
57  N*(mf.qdim)*(mf_target.nbdof/mf_target.qdim)
58  elements (this is not checked by the function!)
59  */
60  template<class VECT1, class VECT2>
61  void compute_gradient(const mesh_fem &mf, const mesh_fem &mf_target,
62  const VECT1 &UU, VECT2 &VV) {
63  typedef typename gmm::linalg_traits<VECT1>::value_type T;
64 
65  size_type N = mf.linked_mesh().dim();
66  size_type qdim = mf.get_qdim();
67  size_type target_qdim = mf_target.get_qdim();
68  size_type qqdimt = qdim * N / target_qdim;
69  std::vector<T> U(mf.nb_basic_dof());
70  std::vector<T> V(mf_target.nb_basic_dof() * qqdimt);
71 
72  mf.extend_vector(UU, U);
73 
74  GMM_ASSERT1(&mf.linked_mesh() == &mf_target.linked_mesh(),
75  "meshes are different.");
76  GMM_ASSERT1(target_qdim == qdim*N || target_qdim == qdim
77  || target_qdim == 1, "invalid Qdim for gradient mesh_fem");
78 
79  base_matrix G;
80  std::vector<T> coeff;
81 
82  bgeot::pgeotrans_precomp pgp = NULL;
83  pfem_precomp pfp = NULL;
84  pfem pf, pf_target, pf_old = NULL, pf_targetold = NULL;
86 
87  for (dal::bv_visitor cv(mf_target.convex_index()); !cv.finished(); ++cv) {
88  pf = mf.fem_of_element(cv);
89  pf_target = mf_target.fem_of_element(cv);
90  if (!pf) continue;
91 
92  GMM_ASSERT1(!(pf_target->need_G()) && pf_target->is_lagrange(),
93  "finite element target not convenient");
94 
95  bgeot::vectors_to_base_matrix(G, mf.linked_mesh().points_of_convex(cv));
96 
97  pgt = mf.linked_mesh().trans_of_convex(cv);
98  if (pf_targetold != pf_target) {
99  pgp = bgeot::geotrans_precomp(pgt, pf_target->node_tab(cv), pf_target);
100  }
101  pf_targetold = pf_target;
102 
103  if (pf_old != pf) {
104  pfp = fem_precomp(pf, pf_target->node_tab(cv), pf_target);
105  }
106  pf_old = pf;
107 
108  gmm::dense_matrix<T> grad(N,qdim), gradt(qdim,N);
109  fem_interpolation_context ctx(pgp, pfp, 0, G, cv, short_type(-1));
110  slice_vector_on_basic_dof_of_element(mf, U, cv, coeff);
111  // gmm::resize(coeff, mf.nb_basic_dof_of_element(cv));
112  // gmm::copy(gmm::sub_vector
113  // (U, gmm::sub_index(mf.ind_basic_dof_of_element(cv))), coeff);
114  for (size_type j = 0; j < pf_target->nb_dof(cv); ++j) {
115  size_type dof_t =
116  mf_target.ind_basic_dof_of_element(cv)[j*target_qdim] * qqdimt;
117  ctx.set_ii(j);
118  pf->interpolation_grad(ctx, coeff, gradt, dim_type(qdim));
119  gmm::copy(gmm::transposed(gradt),grad);
120  std::copy(grad.begin(), grad.end(), V.begin() + dof_t);
121  }
122  }
123 
124  mf_target.reduce_vector(V, VV);
125  }
126 
127  /** Compute the hessian of a field on a getfem::mesh_fem.
128  @param mf the source mesh_fem.
129  @param U the source field.
130  @param mf_target should be a lagrange discontinous element
131  does not work with vectorial elements. ... to be done ...
132  @param V contains on output the gradient of U, evaluated on mf_target.
133 
134  mf_target may have the same Qdim than mf, or it may
135  be a scalar mesh_fem, in which case the derivatives are stored in
136  the order: DxxUx,DxyUx, DyxUx, DyyUx, ...
137 
138  in any case, the size of V should be
139  N*N*(mf.qdim)*(mf_target.nbdof/mf_target.qdim)
140  elements (this is not checked by the function!)
141  */
142  template<class VECT1, class VECT2>
143  void compute_hessian(const mesh_fem &mf, const mesh_fem &mf_target,
144  const VECT1 &UU, VECT2 &VV) {
145  typedef typename gmm::linalg_traits<VECT1>::value_type T;
146 
147  size_type N = mf.linked_mesh().dim();
148  size_type qdim = mf.get_qdim();
149  size_type target_qdim = mf_target.get_qdim();
150  size_type qqdimt = qdim * N * N / target_qdim;
151  std::vector<T> U(mf.nb_basic_dof());
152  std::vector<T> V(mf_target.nb_basic_dof() * qqdimt);
153 
154  mf.extend_vector(UU, U);
155 
156  GMM_ASSERT1(&mf.linked_mesh() == &mf_target.linked_mesh(),
157  "meshes are different.");
158  GMM_ASSERT1(target_qdim == qdim || target_qdim == 1,
159  "invalid Qdim for gradient mesh_fem");
160  base_matrix G;
161  std::vector<T> coeff;
162 
163  bgeot::pgeotrans_precomp pgp = NULL;
164  pfem_precomp pfp = NULL;
165  pfem pf, pf_target, pf_old = NULL, pf_targetold = NULL;
167 
168  for (dal::bv_visitor cv(mf_target.convex_index()); !cv.finished(); ++cv) {
169  pf = mf.fem_of_element(cv);
170  pf_target = mf_target.fem_of_element(cv);
171  GMM_ASSERT1(!(pf_target->need_G()) && pf_target->is_lagrange(),
172  "finite element target not convenient");
173 
174  bgeot::vectors_to_base_matrix(G, mf.linked_mesh().points_of_convex(cv));
175 
176  pgt = mf.linked_mesh().trans_of_convex(cv);
177  if (pf_targetold != pf_target) {
178  pgp = bgeot::geotrans_precomp(pgt, pf_target->node_tab(cv), pf_target);
179  }
180  pf_targetold = pf_target;
181 
182  if (pf_old != pf) {
183  pfp = fem_precomp(pf, pf_target->node_tab(cv), pf_target);
184  }
185  pf_old = pf;
186 
187  gmm::dense_matrix<T> hess(N*N,qdim), hesst(qdim,N*N);
188  fem_interpolation_context ctx(pgp, pfp, 0, G, cv, short_type(-1));
189  slice_vector_on_basic_dof_of_element(mf, U, cv, coeff);
190  // gmm::resize(coeff, mf.nb_basic_dof_of_element(cv));
191  // gmm::copy(gmm::sub_vector
192  // (U, gmm::sub_index(mf.ind_basic_dof_of_element(cv))), coeff);
193  for (size_type j = 0; j < pf_target->nb_dof(cv); ++j) {
194  size_type dof_t
195  = mf_target.ind_basic_dof_of_element(cv)[j*target_qdim] * qqdimt;
196  ctx.set_ii(j);
197  pf->interpolation_hess(ctx, coeff, hesst, dim_type(qdim));
198  gmm::copy(gmm::transposed(hesst), hess);
199  std::copy(hess.begin(), hess.end(), V.begin() + dof_t);
200  }
201  }
202 
203  mf_target.reduce_vector(V, VV);
204  }
205 
206  /**Compute the Von-Mises stress of a field (only valid for
207  linearized elasticity in 3D)
208  */
209  template <typename VEC1, typename VEC2>
211  const getfem::mesh_fem &mf_vm,
212  const VEC1 &U, VEC2 &VM,
213  scalar_type mu=1) {
214  dal::bit_vector bv; bv.add(0, mf_vm.nb_dof());
215  interpolation_von_mises(mf_u, mf_vm, U, VM, bv, mu);
216  }
217 
218  template <typename VEC1, typename VEC2>
219  void interpolation_von_mises(const getfem::mesh_fem &mf_u,
220  const getfem::mesh_fem &mf_vm,
221  const VEC1 &U, VEC2 &VM,
222  const dal::bit_vector &mf_vm_dofs,
223  scalar_type mu=1) {
224 
225  assert(mf_vm.get_qdim() == 1);
226  unsigned N = mf_u.linked_mesh().dim(); assert(N == mf_u.get_qdim());
227  std::vector<scalar_type> DU(mf_vm.nb_dof() * N * N);
228 
229  getfem::compute_gradient(mf_u, mf_vm, U, DU);
230 
231  GMM_ASSERT1(!mf_vm.is_reduced(), "Sorry, to be done");
232 
233  scalar_type vm_min = 0., vm_max = 0.;
234  for (dal::bv_visitor i(mf_vm_dofs); !i.finished(); ++i) {
235  VM[i] = 0;
236  scalar_type sdiag = 0.;
237  for (unsigned j=0; j < N; ++j) {
238  sdiag += DU[i*N*N + j*N + j];
239  for (unsigned k=0; k < N; ++k) {
240  scalar_type e = .5*(DU[i*N*N + j*N + k] + DU[i*N*N + k*N + j]);
241  VM[i] += e*e;
242  }
243  }
244  VM[i] -= 1./N * sdiag * sdiag;
245  vm_min = (i == 0 ? VM[0] : std::min(vm_min, VM[i]));
246  vm_max = (i == 0 ? VM[0] : std::max(vm_max, VM[i]));
247  }
248  cout << "Von Mises : min=" << 4*mu*mu*vm_min << ", max="
249  << 4*mu*mu*vm_max << "\n";
250  gmm::scale(VM, 4*mu*mu);
251  }
252 
253 
254  /** Compute the Von-Mises stress of a field (valid for
255  linearized elasticity in 2D and 3D)
256  */
257  template <typename VEC1, typename VEC2, typename VEC3>
259  const getfem::mesh_fem &mf_vm,
260  const VEC1 &U, VEC2 &VM,
261  const getfem::mesh_fem &mf_lambda,
262  const VEC3 &lambda,
263  const getfem::mesh_fem &mf_mu,
264  const VEC3 &mu,
265  bool tresca) {
266  assert(mf_vm.get_qdim() == 1);
267  typedef typename gmm::linalg_traits<VEC1>::value_type T;
268  size_type N = mf_u.get_qdim();
269  std::vector<T> GRAD(mf_vm.nb_dof()*N*N),
270  LAMBDA(mf_vm.nb_dof()), MU(mf_vm.nb_dof());
271  base_matrix sigma(N,N);
272  base_vector eig(N);
273  if (tresca) interpolation(mf_lambda, mf_vm, lambda, LAMBDA);
274  interpolation(mf_mu, mf_vm, mu, MU);
275  compute_gradient(mf_u, mf_vm, U, GRAD);
276 
277  GMM_ASSERT1(!mf_vm.is_reduced(), "Sorry, to be done");
278  GMM_ASSERT1(N>=2 && N<=3, "Only for 2D and 3D");
279 
280  for (size_type i = 0; i < mf_vm.nb_dof(); ++i) {
281  scalar_type trE = 0, diag = 0;
282  for (unsigned j = 0; j < N; ++j)
283  trE += GRAD[i*N*N + j*N + j];
284  if (tresca)
285  diag = LAMBDA[i]*trE; // calculation of sigma
286  else
287  diag = (-2./3.)*MU[i]*trE; // for the calculation of deviator(sigma)
288  for (unsigned j = 0; j < N; ++j) {
289  for (unsigned k = 0; k < N; ++k) {
290  scalar_type eps = /* 0.5* */ (GRAD[i*N*N + j*N + k] +
291  GRAD[i*N*N + k*N + j]);
292  sigma(j,k) = /* 2* */ MU[i]*eps;
293  }
294  sigma(j,j) += diag;
295  }
296  if (!tresca) {
297  /* von mises: norm(deviator(sigma)) */
298  //gmm::add(gmm::scaled(Id, -gmm::mat_trace(sigma) / N), sigma);
299  if (N==3)
300  VM[i] = sqrt((3./2.)*gmm::mat_euclidean_norm_sqr(sigma));
301  else // for plane strains ( s_33 = -diag )
302  VM[i] = sqrt((3./2.)*(gmm::mat_euclidean_norm_sqr(sigma) + diag*diag));
303  } else {
304  /* else compute the tresca criterion */
305  gmm::symmetric_qr_algorithm(sigma, eig);
306  std::sort(eig.begin(), eig.end());
307  VM[i] = eig.back() - eig.front();
308  }
309  }
310  }
311 }
312 
313 #endif
void set_ii(size_type ii__)
change the current point (assuming a geotrans_precomp_ is used)
structure passed as the argument of fem interpolation functions.
Definition: getfem_fem.h:749
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.
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 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!...
const dal::bit_vector & convex_index() const
Get the set of convexes where a finite element has been assigned.
bool is_reduced() const
Return true if a reduction matrix is applied to the dofs.
Interpolation of fields from a mesh_fem onto another.
Define the getfem::mesh_fem class.
Dense QR factorization.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:243
pfem_precomp fem_precomp(pfem pf, bgeot::pstored_point_tab pspt, dal::pstatic_stored_object dep)
Handles precomputations for FEM.
Definition: getfem_fem.cc:4760
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 compute_gradient(const mesh_fem &mf, const mesh_fem &mf_target, const VECT1 &UU, VECT2 &VV)
Compute the gradient of a field on a getfem::mesh_fem.
void interpolation_von_mises_or_tresca(const getfem::mesh_fem &mf_u, const getfem::mesh_fem &mf_vm, const VEC1 &U, VEC2 &VM, const getfem::mesh_fem &mf_lambda, const VEC3 &lambda, const getfem::mesh_fem &mf_mu, const VEC3 &mu, bool tresca)
Compute the Von-Mises stress of a field (valid for linearized elasticity in 2D and 3D)
void interpolation_von_mises(const getfem::mesh_fem &mf_u, const getfem::mesh_fem &mf_vm, const VEC1 &U, VEC2 &VM, scalar_type mu=1)
Compute the Von-Mises stress of a field (only valid for linearized elasticity in 3D)
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.
void compute_hessian(const mesh_fem &mf, const mesh_fem &mf_target, const VECT1 &UU, VECT2 &VV)
Compute the hessian of a field on a getfem::mesh_fem.