GetFEM  5.5
getfem_mesh_fem_sum.cc
1 /*===========================================================================
2 
3  Copyright (C) 1999-2026 Yves Renard
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, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
21 
23 
24 namespace getfem {
25 
26  void fem_sum::init() {
27  cvr = pfems[0]->ref_convex(cv);
28  dim_ = cvr->structure()->dim();
29  is_equiv = !smart_global_dof_linking_;
30  real_element_defined = true;
31  is_polycomp = is_pol = is_lag = is_standard_fem = false;
32  es_degree = 5; /* humm ... */
33  ntarget_dim = 1;
34 
35  std::stringstream nm;
36  nm << "FEM_SUM(" << pfems[0]->debug_name() << ",";
37  for (size_type i = 1; i < pfems.size(); ++i)
38  nm << pfems[i]->debug_name() << ",";
39  nm << " cv:" << cv << ")";
40  debug_name_ = nm.str();
41 
42  init_cvs_node();
43  for (size_type i = 0; i < pfems.size(); ++i) {
44  GMM_ASSERT1(pfems[i]->target_dim() == 1, "Vectorial fems not supported");
45 
46  for (size_type k = 0; k < pfems[i]->nb_dof(cv); ++k) {
47  add_node(pfems[i]->dof_types()[k], pfems[i]->node_of_dof(cv,k));
48  }
49  }
50  }
51 
52  /* used only when smart_global_dof_linking_ is on */
53  void fem_sum::mat_trans(base_matrix &M,
54  const base_matrix &G,
55  bgeot::pgeometric_trans pgt) const {
56 
57  // cerr << "fem_sum::mat_trans " << debug_name_
58  // << " / smart_global_dof_linking_ = " << smart_global_dof_linking_
59  // << "\n";
60  pdof_description gdof = 0, lagdof = lagrange_dof(dim());
61  std::vector<pdof_description> hermdof(dim());
62  for (dim_type id = 0; id < dim(); ++id)
63  hermdof[id] = derivative_dof(dim(), id);
64  if (pfems.size()) gdof = global_dof(dim());
65  gmm::copy(gmm::identity_matrix(), M);
66  base_vector val(1), val2(1);
67  base_matrix grad(1, dim());
68 
69  // very inefficient, to be optimized ...
70  for (size_type ifem1 = 0, i=0; ifem1 < pfems.size(); ++ifem1) {
71  pfem pf1 = pfems[ifem1];
72  /* find global dofs */
73  for (size_type idof1 = 0; idof1 < pf1->nb_dof(cv); ++idof1, ++i) {
74  if (pf1->dof_types()[idof1] == gdof) {
75  base_vector coeff(pfems[ifem1]->nb_dof(cv));
76  coeff[idof1] = 1.0;
77  fem_interpolation_context fic(pgt, pf1, base_node(dim()), G, cv);
78  for (size_type ifem2 = 0, j=0; ifem2 < pfems.size(); ++ifem2) {
79  pfem pf2 = pfems[ifem2];
80  fem_interpolation_context fic2(pgt, pf2, base_node(dim()), G, cv);
81  for (size_type idof2 = 0; idof2 < pf2->nb_dof(cv); ++idof2, ++j) {
82  pdof_description pdd = pf2->dof_types()[idof2];
83  bool found = false;
84 
85  base_vector coeff2(pfems[ifem2]->nb_dof(cv));
86  coeff2[idof2] = 1.0;
87 
88  if (pdd != gdof) {
89  fic.set_xref(pf2->node_of_dof(cv, idof2));
90  fic2.set_xref(pf2->node_of_dof(cv, idof2));
91  if (dof_weak_compatibility(pdd, lagdof) == 0) {
92  pfems[ifem1]->interpolation(fic, coeff, val, 1);
93 
94  pfems[ifem2]->interpolation(fic2, coeff2, val2, 1);
95 
96  M(i, j) = -val[0]*val2[0];
97  /*if (pf2->nb_dof(cv) > 4)
98  cout << "dof " << idof2 << " ("
99  << pf2->node_of_dof(cv,idof2)
100  << ") " << (void*)&(*pdd)
101  << " compatible with lagrange\n";*/
102  found = true;
103  }
104  else for (size_type id = 0; id < dim(); ++id) {
105  if (dof_weak_compatibility(pdd, hermdof[id]) == 0) {
106  pfems[ifem1]->interpolation_grad(fic, coeff, grad, 1);
107  M(i, j) = -grad(0, id);
108  cout << "dof " << idof2 << "compatible with hermite "
109  << id << "\n";
110  found = true;
111  }
112  }
113  GMM_ASSERT1(found,
114  "Sorry, smart_global_dof_linking not "
115  "compatible with this kind of dof");
116  }
117  }
118  //if (pf2->nb_dof(cv) > 4) cout << " M=" << M << "\n";
119  }
120  }
121  }
122  }
123 
124  // static int cnt=0;
125  // if(++cnt < 40) cout << "fem = " << debug_name_ << ", M = " << M << "\n";
126  }
127 
128  size_type fem_sum::index_of_global_dof(size_type , size_type j) const {
129  for (size_type i = 0; i < pfems.size(); ++i) {
130  size_type nb = pfems[i]->nb_dof(cv);
131  if (j >= nb) j -= pfems[i]->nb_dof(cv);
132  else return pfems[i]->index_of_global_dof(cv, j);
133  }
134  GMM_ASSERT1(false, "incoherent global dof.");
135  }
136 
137  void fem_sum::base_value(const base_node &,
138  base_tensor &) const
139  { GMM_ASSERT1(false, "No base values, real only element."); }
140  void fem_sum::grad_base_value(const base_node &,
141  base_tensor &) const
142  { GMM_ASSERT1(false, "No base values, real only element."); }
143  void fem_sum::hess_base_value(const base_node &,
144  base_tensor &) const
145  { GMM_ASSERT1(false, "No base values, real only element."); }
146 
147  void fem_sum::real_base_value(const fem_interpolation_context &c,
148  base_tensor &t,
149  bool withM) const {
150  bgeot::multi_index mi(2);
151  mi[1] = target_dim(); mi[0] = short_type(nb_dof(0));
152  t.adjust_sizes(mi);
153  base_tensor::iterator it = t.begin(), itf;
154 
155  fem_interpolation_context c0 = c;
156  std::vector<base_tensor> val_e(pfems.size());
157  for (size_type k = 0; k < pfems.size(); ++k) {
158  if (c0.have_pfp()) {
159  c0.set_pfp(fem_precomp(pfems[k], c0.pfp()->get_ppoint_tab(),
160  c0.pfp()));
161  } else { c0.set_pf(pfems[k]); }
162  c0.base_value(val_e[k]);
163  }
164 
165  for (dim_type q = 0; q < target_dim(); ++q) {
166  for (size_type k = 0; k < pfems.size(); ++k) {
167  itf = val_e[k].begin() + q * pfems[k]->nb_dof(cv);
168  for (size_type i = 0; i < pfems[k]->nb_dof(cv); ++i)
169  *it++ = *itf++;
170  }
171  }
172  assert(it == t.end());
173  if (!is_equivalent() && withM) {
174  base_tensor tt(t);
175  t.mat_transp_reduction(tt, c.M(), 0);
176  }
177  //cerr << "fem_sum::real_base_value(" << c.xreal() << ")\n";
178  }
179 
180  void fem_sum::real_grad_base_value(const fem_interpolation_context &c,
181  base_tensor &t, bool withM) const {
182  bgeot::multi_index mi(3);
183  mi[2] = short_type(c.N()); mi[1] = target_dim();
184  mi[0] = short_type(nb_dof(0));
185  t.adjust_sizes(mi);
186  base_tensor::iterator it = t.begin(), itf;
187 
188  fem_interpolation_context c0 = c;
189  std::vector<base_tensor> grad_e(pfems.size());
190  for (size_type k = 0; k < pfems.size(); ++k) {
191  if (c0.have_pfp()) {
192  c0.set_pfp(fem_precomp(pfems[k], c0.pfp()->get_ppoint_tab(),
193  c0.pfp()));
194  } else { c0.set_pf(pfems[k]); }
195  c0.grad_base_value(grad_e[k]);
196  }
197 
198  for (dim_type k = 0; k < c.N() ; ++k) {
199  for (dim_type q = 0; q < target_dim(); ++q) {
200  for (size_type f = 0; f < pfems.size(); ++f) {
201  itf = grad_e[f].begin()
202  + (k * target_dim() + q) * pfems[f]->nb_dof(cv);
203  for (size_type i = 0; i < pfems[f]->nb_dof(cv); ++i)
204  *it++ = *itf++;
205  }
206  }
207  }
208  assert(it == t.end());
209  if (!is_equivalent() && withM) {
210  base_tensor tt(t);
211  t.mat_transp_reduction(tt, c.M(), 0);
212  }
213  }
214 
215  void fem_sum::real_hess_base_value(const fem_interpolation_context &c,
216  base_tensor &t, bool withM) const {
217  t.adjust_sizes(nb_dof(0), target_dim(), gmm::sqr(c.N()));
218  base_tensor::iterator it = t.begin(), itf;
219 
220  fem_interpolation_context c0 = c;
221  std::vector<base_tensor> hess_e(pfems.size());
222  for (size_type k = 0; k < pfems.size(); ++k) {
223  if (c0.have_pfp()) {
224  c0.set_pfp(fem_precomp(pfems[k], c0.pfp()->get_ppoint_tab(),
225  c0.pfp()));
226  } else { c0.set_pf(pfems[k]); }
227  c0.hess_base_value(hess_e[k]);
228  }
229 
230  dim_type NNdim = dim_type(gmm::sqr(c.N())*target_dim());
231  for (dim_type jkq = 0; jkq < NNdim ; ++jkq) {
232  for (size_type f = 0; f < pfems.size(); ++f) {
233  itf = hess_e[f].begin() + (jkq * pfems[f]->nb_dof(cv));
234  for (size_type i = 0; i < pfems[f]->nb_dof(cv); ++i)
235  *it++ = *itf++;
236  }
237  }
238  assert(it == t.end());
239  if (!is_equivalent() && withM) {
240  base_tensor tt(t);
241  t.mat_transp_reduction(tt, c.M(), 0);
242  }
243  }
244 
245  void mesh_fem_sum::clear_build_methods() {
246  for (size_type i = 0; i < build_methods.size(); ++i)
247  del_stored_object(build_methods[i]);
248  build_methods.clear();
249  }
250  void mesh_fem_sum::clear() {
251  mesh_fem::clear();
252  clear_build_methods();
253  situations.clear();
254  is_adapted = false;
255  }
256 
257  DAL_SIMPLE_KEY(special_mflsum_key, pfem);
258 
259  void mesh_fem_sum::adapt() {
260  context_check();
261  clear();
262 
263  for (const mesh_fem *pmf : mfs)
264  GMM_ASSERT1(!(pmf->is_reduced()),
265  "Sorry fem_sum for reduced mesh_fem is not implemented");
266 
267  for (dal::bv_visitor i(linked_mesh().convex_index()); !i.finished(); ++i) {
268  std::vector<pfem> pfems;
269  bool is_cv_dep = false;
270  for (const mesh_fem *pmf : mfs) {
271  if (pmf->convex_index().is_in(i)) {
272  pfem pf = pmf->fem_of_element(i);
273  if (pf->nb_dof(i)) {
274  pfems.push_back(pf);
275  if (pf->is_on_real_element())
276  is_cv_dep = true;
277  }
278  }
279  }
280  if (pfems.size() == 1) {
281  set_finite_element(i, pfems[0]);
282  }
283  else if (pfems.size() > 0) {
284  if (situations.find(pfems) == situations.end() || is_cv_dep) {
285  pfem pf = std::make_shared<fem_sum>(pfems, i,
286  smart_global_dof_linking_);
287  dal::pstatic_stored_object_key
288  pk = std::make_shared<special_mflsum_key>(pf);
289  dal::add_stored_object(pk, pf, pf->ref_convex(0), pf->node_tab(0));
290  build_methods.push_back(pf);
291  situations[pfems] = pf;
292  }
293  set_finite_element(i, situations[pfems]);
294  }
295  }
296  is_adapted = true; touch();
297  }
298 
299 
300 } /* end of namespace getfem. */
301 
bool context_check() const
return true if update_from_context was called
const mesh & linked_mesh() const
Return a reference to the underlying mesh.
void set_finite_element(size_type cv, pfem pf)
Set the finite element method of a convex.
const dal::bit_vector & convex_index() const
Get the set of convexes where a finite element has been assigned.
Implement a special mesh_fem with merges the FEMs of two (or more) mesh_fems.
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
pdof_description derivative_dof(dim_type d, dim_type r)
Description of a unique dof of derivative type.
Definition: getfem_fem.cc:487
pdof_description lagrange_dof(dim_type d)
Description of a unique dof of lagrange type (value at the node).
Definition: getfem_fem.cc:390
pdof_description global_dof(dim_type d)
Description of a global dof, i.e.
Definition: getfem_fem.cc:542
dof_description * pdof_description
Type representing a pointer on a dof_description.
Definition: getfem_fem.h:159
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
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored)
Delete an object and the object which depend on it.
GEneric Tool for Finite Element Methods.