GetFEM  5.5
getfem_fem_global_function.cc
1 /*===========================================================================
2 
3  Copyright (C) 2004-2026 Yves Renard
4  Copyright (C) 2016 Konstantinos Poulios
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 ===========================================================================*/
21 
23 
24 namespace getfem {
25 
26 
27  void fem_global_function::init() {
28  is_pol = is_lag = is_standard_fem = false; es_degree = 5;
29  is_equiv = real_element_defined = true;
30  ntarget_dim = 1; // An extension for vectorial elements should be easy
31 
32  std::stringstream nm;
33  nm << "GLOBAL_FEM(" << (void*)this << ")";
34  debug_name_ = nm.str();
35 
36  GMM_ASSERT1(functions.size() > 0, "Empty list of base functions.");
37  dim_ = functions[0]->dim();
38  for (size_type i=1; i < functions.size(); ++i)
39  GMM_ASSERT1(dim_ == functions[i]->dim(),
40  "Incompatible function space dimensions.");
41 
43  }
44 
45 
46  fem_global_function::fem_global_function
47  (const std::vector<pglobal_function> &funcs, const mesh &m_)
48  : functions(funcs), m(m_), mim(dummy_mesh_im()), has_mesh_im(false) {
49 
50  DAL_STORED_OBJECT_DEBUG_CREATED(this, "Global function fem");
51  GMM_ASSERT1(&m != &dummy_mesh(), "A non-empty mesh object"
52  " is expected.");
53  this->add_dependency(m_);
54  for (const pglobal_function &glob_func : funcs) {
55  std::shared_ptr<const context_dependencies>
56  dep = std::dynamic_pointer_cast<const context_dependencies>(glob_func);
57  if (dep)
58  this->add_dependency(*dep);
59  }
60  init();
61  }
62 
63  fem_global_function::fem_global_function
64  (const std::vector<pglobal_function> &funcs, const mesh_im &mim_)
65  : functions(funcs), m(mim_.linked_mesh()), mim(mim_), has_mesh_im(true) {
66 
67  DAL_STORED_OBJECT_DEBUG_CREATED(this, "Global function fem");
68  GMM_ASSERT1(&mim != &dummy_mesh_im(), "A non-empty mesh_im object"
69  " is expected.");
70  this->add_dependency(mim_);
71  init();
72  }
73 
74  void fem_global_function::update_from_context() const {
75 
76  if (precomps) {
77  for (const auto &cv_precomps : *precomps)
78  for (const auto &keyval : cv_precomps)
79  dal::del_dependency(precomps, keyval.first);
80  precomps->clear();
81  } else {
82  precomps = std::make_shared<precomp_pool>();
83  dal::pstatic_stored_object_key pkey
84  = std::make_shared<precomp_pool_key>(precomps);
85  dal::add_stored_object(pkey, precomps);
86  }
87 
88  size_type nb_total_dof(functions.size());
89  base_node bmin(dim()), bmax(dim());
90  bgeot::rtree boxtree{1E-13};
91  std::map<size_type, std::vector<size_type>> box_to_convexes_map;
92  for (size_type i=0; i < nb_total_dof; ++i) {
93  functions[i]->bounding_box(bmin, bmax);
94  box_to_convexes_map[boxtree.add_box(bmin, bmax, i)].push_back(i);
95  }
96  boxtree.build_tree();
97 
98  size_type max_dof(0);
99  index_of_global_dof_.clear();
100  index_of_global_dof_.resize(m.nb_allocated_convex());
101  for (dal::bv_visitor cv(m.convex_index()); !cv.finished(); ++cv) {
102  GMM_ASSERT1(dim_ == m.structure_of_convex(cv)->dim(),
103  "Convexes of different dimension: to be done");
104  bgeot::pgeometric_trans pgt = m.trans_of_convex(cv);
105 
106  bounding_box(bmin, bmax, m.points_of_convex(cv), pgt);
107 
108  bgeot::rtree::pbox_set boxlst;
109  boxtree.find_intersecting_boxes(bmin, bmax, boxlst);
110  index_of_global_dof_[cv].clear();
111 
112  if (has_mesh_im) {
113  pintegration_method pim = mim.int_method_of_element(cv);
114  GMM_ASSERT1(pim->type() == IM_APPROX, "You have to use approximated "
115  "integration in connection to a fem with global functions");
116  papprox_integration pai = pim->approx_method();
117 
118  for (const auto &box : boxlst) {
119  for (auto candidate : box_to_convexes_map.at(box->id)) {
120  for (size_type k = 0; k < pai->nb_points(); ++k) {
121  base_node gpt = pgt->transform(pai->point(k),
122  m.points_of_convex(cv));
123  if (functions[candidate]->is_in_support(gpt)) {
124  index_of_global_dof_[cv].push_back(candidate);
125  break;
126  }
127  }
128  }
129  }
130  } else { // !has_mesh_im
131  for (const auto &box : boxlst) {
132  for (auto candidate : box_to_convexes_map.at(box->id))
133  index_of_global_dof_[cv].push_back(candidate);
134  }
135  }
136  max_dof = std::max(max_dof, index_of_global_dof_[cv].size());
137  }
138 
139  /** setup global dofs, with dummy coordinates */
140  base_node P(dim()); gmm::fill(P,1./20);
141  std::vector<base_node> node_tab_(max_dof, P);
142  pspt_override = bgeot::store_point_tab(node_tab_);
143  pspt_valid = false;
144  dof_types_.resize(nb_total_dof);
145  std::fill(dof_types_.begin(), dof_types_.end(),
146  global_dof(dim()));
147  }
148 
149  size_type fem_global_function::nb_dof(size_type cv) const {
150  //return functions.size();
151  context_check();
152  return (cv < index_of_global_dof_.size()) ? index_of_global_dof_[cv].size()
153  : size_type(0);
154  }
155 
156  size_type fem_global_function::index_of_global_dof
157  (size_type cv, size_type i) const {
158  //return i;
159  context_check();
160  return (cv < index_of_global_dof_.size() &&
161  i < index_of_global_dof_[cv].size()) ? index_of_global_dof_[cv][i]
162  : size_type(-1);
163  }
164 
165  bgeot::pconvex_ref fem_global_function::ref_convex(size_type cv) const {
166  if (has_mesh_im)
167  return mim.int_method_of_element(cv)->approx_method()->ref_convex();
168  else
169  return bgeot::basic_convex_ref(m.trans_of_convex(cv)->convex_ref());
170  }
171 
173  fem_global_function::node_convex(size_type cv) const {
174  if (m.convex_index().is_in(cv))
176  (dim(), nb_dof(cv), m.structure_of_convex(cv)->nb_faces()));
177  else GMM_ASSERT1(false, "Wrong convex number: " << cv);
178  }
179 
180  void fem_global_function::base_value(const base_node &, base_tensor &) const
181  { GMM_ASSERT1(false, "No base values, real only element."); }
182  void fem_global_function::grad_base_value(const base_node &,
183  base_tensor &) const
184  { GMM_ASSERT1(false, "No grad values, real only element."); }
185  void fem_global_function::hess_base_value(const base_node &,
186  base_tensor &) const
187  { GMM_ASSERT1(false, "No hess values, real only element."); }
188 
189  void fem_global_function::real_base_value(const fem_interpolation_context& c,
190  base_tensor &t, bool) const {
191  assert(target_dim() == 1);
192  size_type cv = c.convex_num();
193  size_type nbdof = nb_dof(cv);
194  t.adjust_sizes(nbdof, target_dim());
195  if (c.have_pfp() && c.ii() != size_type(-1)) {
196  GMM_ASSERT1(precomps, "Internal error");
197  if (precomps->size() == 0)
198  precomps->resize(m.nb_allocated_convex());
199  GMM_ASSERT1(precomps->size() == m.nb_allocated_convex(), "Internal error");
200  const bgeot::pstored_point_tab ptab = c.pfp()->get_ppoint_tab();
201  auto it = (*precomps)[cv].find(ptab);
202  if (it == (*precomps)[cv].end()) {
203  it = (*precomps)[cv].emplace(ptab, precomp_data()).first;
204  dal::add_dependency(precomps, ptab);
205  // we could have added the dependency to this->shared_from_this()
206  // instead, but there is a risk that this will shadow the same
207  // dependency through a different path, so that it becomes dangerous
208  // to delete the dependency later
209  }
210  if (it->second.val.size() == 0) {
211  it->second.val.resize(ptab->size());
212  base_matrix G;
213  bgeot::vectors_to_base_matrix(G, m.points_of_convex(cv));
214  for (size_type k = 0; k < ptab->size(); ++k) {
216  ctx(m.trans_of_convex(cv), shared_from_this(), (*ptab)[k], G, cv);
217  real_base_value(ctx, it->second.val[k]);
218  }
219  }
220  gmm::copy(it->second.val[c.ii()].as_vector(), t.as_vector());
221  } else
222  for (size_type i=0; i < nbdof; ++i) {
223  /*cerr << "fem_global_function: real_base_value(" << c.xreal() << ")\n";
224  if (c.have_G()) cerr << "G = " << c.G() << "\n";
225  else cerr << "no G\n";*/
226  t[i] = functions[index_of_global_dof_[cv][i]]->val(c);
227  }
228  }
229 
230  void fem_global_function::real_grad_base_value
231  (const fem_interpolation_context& c, base_tensor &t, bool) const {
232  assert(target_dim() == 1);
233  size_type cv = c.convex_num();
234  size_type nbdof = nb_dof(cv);
235  t.adjust_sizes(nbdof, target_dim(), dim());
236  if (c.have_pfp() && c.ii() != size_type(-1)) {
237  GMM_ASSERT1(precomps, "Internal error");
238  if (precomps->size() == 0)
239  precomps->resize(m.nb_allocated_convex());
240  GMM_ASSERT1(precomps->size() == m.nb_allocated_convex(), "Internal error");
241  const bgeot::pstored_point_tab ptab = c.pfp()->get_ppoint_tab();
242  auto it = (*precomps)[cv].find(ptab);
243  if (it == (*precomps)[cv].end()) {
244  it = (*precomps)[cv].emplace(ptab, precomp_data()).first;
245  dal::add_dependency(precomps, ptab);
246  }
247  if (it->second.grad.size() == 0) {
248  it->second.grad.resize(ptab->size());
249  base_matrix G;
250  bgeot::vectors_to_base_matrix(G, m.points_of_convex(cv));
251  for (size_type k = 0; k < ptab->size(); ++k) {
253  ctx(m.trans_of_convex(cv), shared_from_this(), (*ptab)[k], G, cv);
254  real_grad_base_value(ctx, it->second.grad[k]);
255  }
256  }
257  gmm::copy(it->second.grad[c.ii()].as_vector(), t.as_vector());
258  } else {
259  base_small_vector G(dim());
260  for (size_type i=0; i < nbdof; ++i) {
261  functions[index_of_global_dof_[cv][i]]->grad(c,G);
262  for (size_type j=0; j < dim(); ++j)
263  t[j*nbdof + i] = G[j];
264  }
265  }
266  }
267 
268  void fem_global_function::real_hess_base_value
269  (const fem_interpolation_context &c, base_tensor &t, bool) const {
270  assert(target_dim() == 1);
271  size_type cv = c.convex_num();
272  size_type nbdof = nb_dof(cv);
273  t.adjust_sizes(nbdof, target_dim(), gmm::sqr(dim()));
274  if (c.have_pfp() && c.ii() != size_type(-1)) {
275  GMM_ASSERT1(precomps, "Internal error");
276  if (precomps->size() == 0)
277  precomps->resize(m.nb_allocated_convex());
278  GMM_ASSERT1(precomps->size() == m.nb_allocated_convex(), "Internal error");
279  const bgeot::pstored_point_tab ptab = c.pfp()->get_ppoint_tab();
280  auto it = (*precomps)[cv].find(ptab);
281  if (it == (*precomps)[cv].end()) {
282  it = (*precomps)[cv].emplace(ptab, precomp_data()).first;
283  dal::add_dependency(precomps, ptab);
284  }
285  if (it->second.hess.size() == 0) {
286  it->second.hess.resize(ptab->size());
287  base_matrix G;
288  bgeot::vectors_to_base_matrix(G, m.points_of_convex(cv));
289  for (size_type k = 0; k < ptab->size(); ++k) {
291  ctx(m.trans_of_convex(cv), shared_from_this(), (*ptab)[k], G, cv);
292  real_hess_base_value(ctx, it->second.hess[k]);
293  }
294  }
295  gmm::copy(it->second.hess[c.ii()].as_vector(), t.as_vector());
296  } else {
297  base_matrix H(dim(),dim());
298  for (size_type i=0; i < nbdof; ++i) {
299  functions[index_of_global_dof_[cv][i]]->hess(c,H);
300  for (size_type jk=0; jk < size_type(dim()*dim()); ++jk)
301  t[jk*nbdof + i] = H[jk];
302  }
303  }
304  }
305 
306 
307  DAL_SIMPLE_KEY(special_fem_globf_key, pfem);
308 
309  pfem new_fem_global_function(const std::vector<pglobal_function> &funcs,
310  const mesh &m) {
311  pfem pf = std::make_shared<fem_global_function>(funcs, m);
312  dal::pstatic_stored_object_key
313  pk = std::make_shared<special_fem_globf_key>(pf);
314  dal::add_stored_object(pk, pf);
315  return pf;
316  }
317 
318  pfem new_fem_global_function(const std::vector<pglobal_function> &funcs,
319  const mesh_im &mim) {
320  pfem pf = std::make_shared<fem_global_function>(funcs, mim);
321  dal::pstatic_stored_object_key
322  pk = std::make_shared<special_fem_globf_key>(pf);
323  dal::add_stored_object(pk, pf);
324  return pf;
325  }
326 
327 }
328 
329 /* end of namespace getfem */
Balanced tree of n-dimensional rectangles.
Definition: bgeot_rtree.h:97
virtual void update_from_context() const
this function has to be defined and should update the object when the context is modified.
structure passed as the argument of fem interpolation functions.
Definition: getfem_fem.h:749
Describe an integration method linked to a mesh.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:98
Define mesh_fem whose base functions are global function given by the user.
pdof_description global_dof(dim_type d)
Description of a global dof, i.e.
Definition: getfem_fem.cc:542
size_type convex_num() const
get the current convex number
Definition: getfem_fem.cc:52
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:243
bool have_pfp() const
true if a fem_precomp_ has been supplied.
Definition: getfem_fem.h:759
pfem_precomp pfp() const
get the current fem_precomp_
Definition: getfem_fem.h:793
dim_type dim() const
dimension of the reference element.
Definition: getfem_fem.h:310
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:48
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
pconvex_ref basic_convex_ref(pconvex_ref cvr)
return the associated order 1 reference convex.
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
void add_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
Add a dependency, object o1 will depend on object o2.
bool del_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
remove a dependency.
GEneric Tool for Finite Element Methods.
const mesh_im & dummy_mesh_im()
Dummy mesh_im for default parameter of functions.
pfem new_fem_global_function(const std::vector< pglobal_function > &funcs, const mesh &m)
create a new global function FEM.