GetFEM++  5.3
bgeot_geotrans_inv.cc
1 /*===========================================================================
2 
3  Copyright (C) 2000-2017 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, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
24 #include "getfem/bgeot_torus.h"
25 #include "gmm/gmm_solver_bfgs.h"
26 
27 using namespace gmm;
28 using namespace std;
29 
30 namespace bgeot
31 {
32  bool geotrans_inv_convex::invert(const base_node& n, base_node& n_ref,
33  scalar_type IN_EPS) {
34  assert(pgt);
35  n_ref.resize(pgt->structure()->dim());
36  bool converged = true;
37  if (pgt->is_linear()) {
38  return invert_lin(n, n_ref,IN_EPS);
39  } else {
40  return invert_nonlin(n, n_ref,IN_EPS,converged,true);
41  }
42  }
43 
44  bool geotrans_inv_convex::invert(const base_node& n, base_node& n_ref,
45  bool &converged,
46  scalar_type IN_EPS) {
47  assert(pgt);
48  n_ref.resize(pgt->structure()->dim());
49  converged = true;
50  if (pgt->is_linear()) {
51  return invert_lin(n, n_ref,IN_EPS);
52  } else return invert_nonlin(n, n_ref,IN_EPS,converged, false);
53  }
54 
55  bool point_in_convex(const geometric_trans &geoTrans,
56  const base_node &x,
57  scalar_type res,
58  scalar_type IN_EPS) {
59  // Test un peu sevère peut-être en ce qui concerne res.
60  return (geoTrans.convex_ref()->is_in(x) < IN_EPS) && (res < IN_EPS);
61  }
62 
63  /* inversion for linear geometric transformations */
64  bool geotrans_inv_convex::invert_lin(const base_node& n, base_node& n_ref,
65  scalar_type IN_EPS) {
66  base_node y(n); for (size_type i=0; i < N; ++i) y[i] -= G(i,0);
67  mult(transposed(B), y, n_ref);
68  y = pgt->transform(n_ref, G);
69  add(scaled(n, -1.0), y);
70 
71  return point_in_convex(*pgt, n_ref, vect_norm2(y), IN_EPS);
72  }
73 
74  void geotrans_inv_convex::update_B() {
75  if (P != N) {
76  pgt->compute_K_matrix(G, pc, K);
77  gmm::mult(gmm::transposed(K), K, CS);
78  bgeot::lu_inverse(&(*(CS.begin())), P);
79  gmm::mult(K, CS, B);
80  }
81  else {
82  // L'inversion peut être optimisée par le non calcul global de B
83  // et la resolution d'un système linéaire.
84  base_matrix KT(K.nrows(), K.ncols());
85  pgt->compute_K_matrix(G, pc, KT);
86  gmm::copy(gmm::transposed(KT), K);
87  gmm::copy(K, B);
88  bgeot::lu_inverse(&(*(K.begin())), P); B.swap(K);
89  }
90  }
91 
92  void geotrans_inv_convex::set_projection_into_element(bool active){
93  nonlinear_storage.project_into_element = active;
94  }
95 
96  class geotrans_inv_convex_bfgs {
98  base_node xreal;
99  public:
100  geotrans_inv_convex_bfgs(geotrans_inv_convex &gic_,
101  const base_node &xr) : gic(gic_), xreal(xr) {}
102  scalar_type operator()(const base_node& x) const {
103  base_node r = gic.pgt->transform(x, gic.G) - xreal;
104  return gmm::vect_norm2_sqr(r)/2.;
105  }
106  void operator()(const base_node& x, base_small_vector& gr) const {
107  gic.pgt->poly_vector_grad(x, gic.pc);
108  gic.update_B();
109  base_node r = gic.pgt->transform(x, gic.G) - xreal;
110  gr.resize(x.size());
111  gmm::mult(gmm::transposed(gic.K), r, gr);
112  }
113  };
114 
115  nonlinear_storage_struct::linearised_structure::linearised_structure
116  (const convex_ind_ct &direct_points_indices,
117  const stored_point_tab &reference_nodes,
118  const std::vector<base_node> &real_nodes) :
119  diff(real_nodes.begin()->size()), diff_ref(direct_points_indices.size()-1) {
120  auto n_points = direct_points_indices.size();
121  std::vector<base_node> direct_points;
122  std::vector<base_node> direct_points_ref;
123  direct_points.reserve(n_points);
124  direct_points_ref.reserve(n_points);
125 
126  for (auto i : direct_points_indices) {
127  direct_points.push_back(real_nodes[i]);
128  direct_points_ref.push_back(reference_nodes[i]);
129  }
130 
131  auto N = direct_points.begin()->size();
132  auto N_ref = direct_points_ref.begin()->size();
133  base_matrix K_linear(N, n_points - 1);
134  B_linear.base_resize(N, n_points - 1);
135  K_ref_linear.base_resize(N_ref, n_points - 1);
136  P_linear = direct_points[0];
137  P_ref_linear = direct_points_ref[0];
138 
139  for (size_type i = 1; i < n_points; ++i) {
140  add(direct_points[i], scaled(P_linear, -1.0), mat_col(K_linear, i - 1));
141  add(direct_points_ref[i], scaled(P_ref_linear, -1.0),
142  mat_col(K_ref_linear, i - 1));
143  }
144 
145  if (K_linear.nrows() == K_linear.ncols()) {
146  lu_inverse(K_linear);
147  copy(transposed(K_linear), B_linear);
148  }
149  else {
150  base_matrix temp(n_points - 1, n_points - 1);
151  mult(transposed(K_linear), K_linear, temp);
152  lu_inverse(temp);
153  mult(K_linear, temp, B_linear);
154  }
155  }
156 
157  void nonlinear_storage_struct::linearised_structure::invert
158  (const base_node &x_real, base_node &x_ref, scalar_type /* IN_EPS */) const {
159  add(x_real, scaled(P_linear, -1.0), diff);
160  mult(transposed(B_linear), diff, diff_ref);
161  mult(K_ref_linear, diff_ref, x_ref);
162  add(P_ref_linear, x_ref);
163  }
164 
165  void project_into_convex(base_node &x, const geometric_trans *pgeo_trans,
166  bool project) {
167  if (project == false) return;
168 
169  auto dim = pgeo_trans->dim();
170 
171  for (auto d = 0; d < dim; ++d) {
172  if (x[d] < 0.0) x[d] = 0.0;
173  if (x[d] > 1.0) x[d] = 1.0;
174  }
175 
176  auto poriginal_trans = pgeo_trans;
177 
178  if (auto ptorus_trans = dynamic_cast<const torus_geom_trans*>(pgeo_trans)) {
179  poriginal_trans = ptorus_trans->get_original_transformation().get();
180  }
181 
182  auto pbasic_convex_ref = basic_convex_ref(poriginal_trans->convex_ref());
183  auto nb_simplices = pbasic_convex_ref->simplexified_convex()->nb_convex();
184 
185  if (nb_simplices == 1) { // simplex
186  auto sum_coordinates = 0.0;
187 
188  for (auto d = 0; d < dim; ++d) sum_coordinates += x[d];
189 
190  if (sum_coordinates > 1.0) scale(x, 1.0 / sum_coordinates);
191  }
192  else if ((dim == 3) && (nb_simplices != 4)) { // prism
193  auto sum_coordinates = x[0] + x[1];
194 
195  if (sum_coordinates > 1.0) {
196  x[0] /= sum_coordinates;
197  x[1] /= sum_coordinates;
198  }
199  }
200  }
201 
202  void find_initial_guess(base_node &x,
203  nonlinear_storage_struct &storage,
204  const base_node &xreal,
205  const base_matrix &G,
206  const geometric_trans *pgt,
207  scalar_type IN_EPS) {
208  storage.x_ref = pgt->geometric_nodes()[0];
209 
210  auto res = vect_dist2(mat_col(G, 0), xreal);
211  double res0;
212 
213  for (size_type j = 1; j < pgt->nb_points(); ++j) {
214  res0 = vect_dist2(mat_col(G, j), xreal);
215  if (res > res0) {
216  res = res0;
217  storage.x_ref = pgt->geometric_nodes()[j];
218  }
219  }
220 
221  res0 = std::numeric_limits<scalar_type>::max();
222 
223  if (storage.plinearised_structure != nullptr) {
224  storage.plinearised_structure->invert(xreal, x, IN_EPS);
225  project_into_convex(x, pgt, storage.project_into_element);
226  res0 = vect_dist2(pgt->transform(x, G), xreal);
227  }
228 
229  if (res < res0) copy(storage.x_ref, x);
230  x *= 0.999888783; // For pyramid element to avoid the singularity
231  }
232 
233 
234  /* inversion for non-linear geometric transformations
235  (Newton on Grad(pgt)(y - pgt(x)) = 0 )
236  */
237  bool geotrans_inv_convex::invert_nonlin(const base_node& xreal,
238  base_node& x, scalar_type IN_EPS,
239  bool &converged, bool /* throw_except */) {
240  converged = true;
241  find_initial_guess(x, nonlinear_storage, xreal, G, pgt.get(), IN_EPS);
242  add(pgt->transform(x, G), scaled(xreal, -1.0), nonlinear_storage.diff);
243  auto res = vect_norm2(nonlinear_storage.diff);
244  auto res0 = std::numeric_limits<scalar_type>::max();
245  double factor = 1.0;
246 
247  while (res > IN_EPS) {
248  if ((abs(res - res0) < IN_EPS) || (factor < IN_EPS)) {
249  converged = false;
250  return point_in_convex(*pgt, x, res, IN_EPS);
251  }
252 
253  if (res > res0) {
254  add(scaled(nonlinear_storage.x_ref, factor), x);
255  nonlinear_storage.x_real = pgt->transform(x, G);
256  add(nonlinear_storage.x_real, scaled(xreal, -1.0),
257  nonlinear_storage.diff);
258  factor *= 0.5;
259  }
260  else {
261  if (factor < 1.0-IN_EPS) factor = 2.0;
262  res0 = res;
263  }
264  pgt->poly_vector_grad(x, pc);
265  update_B();
266  mult(transposed(B), nonlinear_storage.diff, nonlinear_storage.x_ref);
267  add(scaled(nonlinear_storage.x_ref, -1.0 * factor), x);
268  project_into_convex(x, pgt.get(), nonlinear_storage.project_into_element);
269  nonlinear_storage.x_real = pgt->transform(x, G);
270  add(nonlinear_storage.x_real, scaled(xreal, -1.0),
271  nonlinear_storage.diff);
272  res = vect_norm2(nonlinear_storage.diff);
273  }
274 
275  return point_in_convex(*pgt, x, res, IN_EPS);
276  }
277 
278 } /* end of namespace bgeot. */
virtual void poly_vector_grad(const base_node &pt, base_matrix &val) const =0
Gives the gradient of the functions vector at a certain point.
pconvex_ref basic_convex_ref(pconvex_ref cvr)
return the associated order 1 reference convex.
Description of a geometric transformation between a reference element and a real element.
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2_sqr(const V &v)
squared Euclidean norm of a vector.
Definition: gmm_blas.h:544
Point tab storage.
does the inversion of the geometric transformation for a given convex
base_node transform(const base_node &pt, const CONT &PTAB) const
Apply the geometric transformation to point pt, PTAB contains the points of the real convex...
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
Definition: gmm_blas.h:597
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:557
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
Inversion of geometric transformations.
void copy(const L1 &l1, L2 &l2)
*/
Definition: gmm_blas.h:977
size_type nb_points() const
Number of geometric nodes.
Mesh structure definition.
const stored_point_tab & geometric_nodes() const
Gives the array of geometric nodes (on reference convex)
pconvex_ref convex_ref() const
Pointer on the convex of reference.
Implements BFGS (Broyden, Fletcher, Goldfarb, Shanno) algorithm.
Basic Geometric Tools.
dim_type dim() const
Dimension of the reference element.
Provides mesh of torus.
void add(const L1 &l1, L2 &l2)
*/
Definition: gmm_blas.h:1268