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