GetFEM++  5.3
bgeot_geometric_trans.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 
22 
23 #include "getfem/dal_singleton.h"
24 #include "getfem/dal_tree_sorted.h"
27 #include "getfem/bgeot_torus.h"
28 
29 namespace bgeot {
30 
31  std::vector<scalar_type>& __aux1(){
32  DEFINE_STATIC_THREAD_LOCAL(std::vector<scalar_type>, v);
33  return v;
34  }
35 
36  std::vector<scalar_type>& __aux2(){
37  DEFINE_STATIC_THREAD_LOCAL(std::vector<scalar_type>, v);
38  return v;
39  }
40 
41  std::vector<scalar_type>& __aux3(){
42  DEFINE_STATIC_THREAD_LOCAL(std::vector<scalar_type>, v);
43  return v;
44  }
45 
46  std::vector<long>& __ipvt_aux(){
47  DEFINE_STATIC_THREAD_LOCAL(std::vector<long>, vi);
48  return vi;
49  }
50 
51  // Optimized matrix mult for small matrices. To be verified.
52  // Multiply the matrix A of size MxN by B of size NxP in C of size MxP
53  void mat_mult(const scalar_type *A, const scalar_type *B, scalar_type *C,
54  size_type M, size_type N, size_type P) {
55  if (N != 0) {
56  auto itC = C; auto itB = B;
57  for (size_type j = 0; j < P; ++j, itB += N)
58  for (size_type i = 0; i < M; ++i, ++itC) {
59  auto itA = A+i, itB1 = itB;
60  *itC = (*itA) * (*itB1);
61  for (size_type k = 1; k < N; ++k)
62  { itA += M; ++itB1; *itC += (*itA) * (*itB1); }
63  }
64  } else std::fill(C, C+M*P, scalar_type(0));
65  }
66 
67  // Optimized matrix mult for small matrices.
68  // Multiply the matrix A of size MxN by the transpose of B of size PxN
69  // in C of size MxP
70  void mat_tmult(const scalar_type *A, const scalar_type *B, scalar_type *C,
71  size_type M, size_type N, size_type P) {
72  auto itC = C;
73  switch (N) {
74  case 0 : std::fill(C, C+M*P, scalar_type(0)); break;
75  case 1 :
76  for (size_type j = 0; j < P; ++j)
77  for (size_type i = 0; i < M; ++i, ++itC) {
78  auto itA = A+i, itB = B+j;
79  *itC = (*itA) * (*itB);
80  }
81  break;
82  case 2 :
83  for (size_type j = 0; j < P; ++j)
84  for (size_type i = 0; i < M; ++i, ++itC) {
85  auto itA = A+i, itB = B+j;
86  *itC = (*itA) * (*itB);
87  itA += M; itB += P; *itC += (*itA) * (*itB);
88  }
89  break;
90  case 3 :
91  for (size_type j = 0; j < P; ++j)
92  for (size_type i = 0; i < M; ++i, ++itC) {
93  auto itA = A+i, itB = B+j;
94  *itC = (*itA) * (*itB);
95  itA += M; itB += P; *itC += (*itA) * (*itB);
96  itA += M; itB += P; *itC += (*itA) * (*itB);
97  }
98  break;
99  default :
100  for (size_type j = 0; j < P; ++j)
101  for (size_type i = 0; i < M; ++i, ++itC) {
102  auto itA = A+i, itB = B+j;
103  *itC = (*itA) * (*itB);
104  for (size_type k = 1; k < N; ++k)
105  { itA += M; itB += P; *itC += (*itA) * (*itB); }
106  }
107  }
108  }
109 
110 
111 
112 
113  // Optimized lu_factor for small square matrices
114  size_type lu_factor(scalar_type *A, std::vector<long> &ipvt,
115  size_type N) {
116  size_type info(0), i, j, jp, N_1 = N-1;
117 
118  if (N) {
119  for (j = 0; j < N_1; ++j) {
120  auto it = A + (j*(N+1));
121  scalar_type max = gmm::abs(*it); jp = j;
122  for (i = j+1; i < N; ++i) {
123  scalar_type ap = gmm::abs(*(++it));
124  if (ap > max) { jp = i; max = ap; }
125  }
126  ipvt[j] = long(jp + 1);
127 
128  if (max == scalar_type(0)) { info = j + 1; break; }
129  if (jp != j) {
130  auto it1 = A+jp, it2 = A+j;
131  for (i = 0; i < N; ++i, it1+=N, it2+=N) std::swap(*it1, *it2);
132  }
133  it = A + (j*(N+1)); max = *it++;
134  for (i = j+1; i < N; ++i) *it++ /= max;
135  auto it22 = A + (j*N + j+1), it11 = it22;
136  auto it3 = A + ((j+1)*N+j);
137  for (size_type l = j+1; l < N; ++l) {
138  it11 += N;
139  auto it1 = it11, it2 = it22;
140  scalar_type a = *it3; it3 += N;
141  for (size_type k = j+1; k < N; ++k) *it1++ -= *it2++ * a;
142  }
143 
144  }
145  ipvt[N-1] = long(N);
146  }
147  return info;
148  }
149 
150  static void lower_tri_solve(const scalar_type *T, scalar_type *x, int N,
151  bool is_unit) {
152  scalar_type x_j;
153  for (int j = 0; j < N; ++j) {
154  auto itc = T + j*N, it = itc+(j+1), ite = itc+N;
155  auto itx = x + j;
156  if (!is_unit) *itx /= itc[j];
157  x_j = *itx++;
158  for (; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
159  }
160  }
161 
162  static void upper_tri_solve(const scalar_type *T, scalar_type *x, int N,
163  bool is_unit) {
164  scalar_type x_j;
165  for (int j = N - 1; j >= 0; --j) {
166  auto itc = T + j*N, it = itc, ite = itc+j;
167  auto itx = x;
168  if (!is_unit) x[j] /= itc[j];
169  for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
170  }
171  }
172 
173  static void lu_solve(const scalar_type *LU, const std::vector<long> &ipvt,
174  scalar_type *x, scalar_type *b, int N) {
175  std::copy(b, b+N, x);
176  for(int i = 0; i < N; ++i)
177  { long perm = ipvt[i]-1; if(i != perm) std::swap(x[i], x[perm]); }
178  bgeot::lower_tri_solve(LU, x, N, true);
179  bgeot::upper_tri_solve(LU, x, N, false);
180  }
181 
182  scalar_type lu_det(const scalar_type *LU, const std::vector<long> &ipvt,
183  size_type N) {
184  scalar_type det(1);
185  for (size_type j = 0; j < N; ++j) det *= *(LU+j*(N+1));
186  for(long i = 0; i < long(N); ++i) if (i != ipvt[i]-1) { det = -det; }
187  return det;
188  }
189 
190  scalar_type lu_det(const scalar_type *A, size_type N) {
191  switch (N) {
192  case 1: return *A;
193  case 2: return (*A) * (A[3]) - (A[1]) * (A[2]);
194  case 3:
195  {
196  scalar_type a0 = A[4]*A[8] - A[5]*A[7], a3 = A[5]*A[6] - A[3]*A[8];
197  scalar_type a6 = A[3]*A[7] - A[4]*A[6];
198  return A[0] * a0 + A[1] * a3 + A[2] * a6;
199  }
200  default:
201  {
202  size_type NN = N*N;
203  if (__aux1().size() < NN) __aux1().resize(N*N);
204  std::copy(A, A+NN, __aux1().begin());
205  __ipvt_aux().resize(N);
206  lu_factor(&(*(__aux1().begin())), __ipvt_aux(), N);
207  return lu_det(&(*(__aux1().begin())), __ipvt_aux(), N);
208  }
209  }
210  }
211 
212  void lu_inverse(const scalar_type *LU, const std::vector<long> &ipvt,
213  scalar_type *A, size_type N) {
214  __aux2().resize(N); gmm::clear(__aux2());
215  __aux3().resize(N);
216  for(size_type i = 0; i < N; ++i) {
217  __aux2()[i] = scalar_type(1);
218  bgeot::lu_solve(LU, ipvt, A+i*N, &(*(__aux2().begin())), int(N));
219  __aux2()[i] = scalar_type(0);
220  }
221  }
222 
223  scalar_type lu_inverse(scalar_type *A, size_type N, bool doassert) {
224  switch (N) {
225  case 1:
226  {
227  scalar_type det = *A;
228  GMM_ASSERT1(det != scalar_type(0), "Non invertible matrix");
229  *A = scalar_type(1)/det;
230  return det;
231  }
232  case 2:
233  {
234  scalar_type a = *A, b = A[2], c = A[1], d = A[3];
235  scalar_type det = a * d - b * c;
236  GMM_ASSERT1(det != scalar_type(0), "Non invertible matrix");
237  *A++ = d/det; *A++ /= -det; *A++ /= -det; *A = a/det;
238  return det;
239  }
240  case 3:
241  {
242  scalar_type a0 = A[4]*A[8] - A[5]*A[7], a1 = A[5]*A[6] - A[3]*A[8];
243  scalar_type a2 = A[3]*A[7] - A[4]*A[6];
244  scalar_type det = A[0] * a0 + A[1] * a1 + A[2] * a2;
245  scalar_type a18 = 1 / det;
246  GMM_ASSERT1(det != scalar_type(0), "Non invertible matrix");
247  scalar_type a3 = (A[2]*A[7] - A[1]*A[8]), a6 = (A[1]*A[5] - A[2]*A[4]);
248  scalar_type a4 = (A[0]*A[8] - A[2]*A[6]), a7 = (A[2]*A[3] - A[0]*A[5]);
249  scalar_type a5 = (A[1]*A[6] - A[0]*A[7]), a8 = (A[0]*A[4] - A[1]*A[3]);
250  *A++ = a0 / det; *A++ = a3 / det; *A++ = a6 / det;
251  *A++ = a1 / det; *A++ = a4 / det; *A++ = a7 / det;
252  *A++ = a2 / det; *A++ = a5 / det; *A++ = a8 / det;
253  return det;
254  }
255  default:
256  {
257  size_type NN = N*N;
258  if (__aux1().size() < NN) __aux1().resize(NN);
259  std::copy(A, A+NN, __aux1().begin());
260  __ipvt_aux().resize(N);
261  size_type info = lu_factor(&(*(__aux1().begin())), __ipvt_aux(), N);
262  if (doassert) GMM_ASSERT1(!info, "Non invertible matrix, pivot = "
263  << info);
264  if (!info) lu_inverse(&(*(__aux1().begin())), __ipvt_aux(), A, N);
265  return lu_det(&(*(__aux1().begin())), __ipvt_aux(), N);
266  }
267  }
268  }
269 
270 
271 
273  (const base_matrix &G, const base_matrix &pc, base_matrix &K) const {
274  // gmm::mult(G, pc, K);
275  // Faster than the lapack call on my config ...
276  size_type N=gmm::mat_nrows(G), P=gmm::mat_nrows(pc), Q=gmm::mat_ncols(pc);
277  if (N && P && Q) {
278  auto itK = K.begin();
279  for (size_type j = 0; j < Q; ++j) {
280  auto itpc_j = pc.begin() + j*P, itG_b = G.begin();
281  for (size_type i = 0; i < N; ++i, ++itG_b) {
282  auto itG = itG_b, itpc = itpc_j;
283  register scalar_type a = *(itG) * (*itpc);
284  for (size_type k = 1; k < P; ++k)
285  { itG += N; a += *(itG) * (*++itpc); }
286  *itK++ = a;
287  }
288  }
289  } else gmm::clear(K);
290  }
291 
293  if (!have_xref()) {
294  if (pspt_) xref_ = (*pspt_)[ii_];
295  else GMM_ASSERT1(false, "Missing xref");
296  }
297  return xref_;
298  }
299 
301  if (!have_xreal()) {
302  if (have_pgp()) {
303  xreal_ = pgp_->transform(ii_, G());
304  } else xreal_ = pgt()->transform(xref(),G());
305  }
306  return xreal_;
307  }
308 
310  GMM_ASSERT1(have_G(),
311  "Convex center can be provided only if matrix G is available");
312  if (!have_cv_center_) {
313  cv_center_.resize(G().nrows());
314  size_type nb_pts = G().ncols();
315  for (size_type i=0; i < nb_pts; i++)
316  gmm::add(gmm::mat_col(G(),i), cv_center_);
317  gmm::scale(cv_center_, scalar_type(1)/scalar_type(nb_pts));
318  have_cv_center_ = true;
319  }
320  return cv_center_;
321  }
322 
323  void geotrans_interpolation_context::compute_J() const {
324  GMM_ASSERT1(have_G() && have_pgt(), "Unable to compute J\n");
325  size_type P = pgt_->structure()->dim();
326  const base_matrix &KK = K();
327  if (P != N()) {
328  B_factors.base_resize(P, P);
329  gmm::mult(gmm::transposed(KK), KK, B_factors);
330  // gmm::abs below because on flat convexes determinant could be -1e-27.
331  J__ = J_ =::sqrt(gmm::abs(bgeot::lu_inverse(&(*(B_factors.begin())), P)));
332  } else {
333  auto it = &(*(KK.begin()));
334  switch (P) {
335  case 1: J__ = *it; break;
336  case 2: J__ = (*it) * (it[3]) - (it[1]) * (it[2]); break;
337  case 3:
338  {
339  B_.base_resize(P, P); // co-factors
340  auto itB = B_.begin();
341  scalar_type a0 = itB[0] = it[4]*it[8] - it[5]*it[7];
342  scalar_type a1 = itB[1] = it[5]*it[6] - it[3]*it[8];
343  scalar_type a2 = itB[2] = it[3]*it[7] - it[4]*it[6];
344  J__ = it[0] * a0 + it[1] * a1 + it[2] * a2;
345  } break;
346  default:
347  B_factors.base_resize(P, P); // store factorization for B computation
348  gmm::copy(gmm::transposed(KK), B_factors);
349  ipvt.resize(P);
350  bgeot::lu_factor(&(*(B_factors.begin())), ipvt, P);
351  J__ = bgeot::lu_det(&(*(B_factors.begin())), ipvt, P);
352  break;
353  }
354  J_ = gmm::abs(J__);
355  }
356  have_J_ = true;
357  }
358 
359  const base_matrix& geotrans_interpolation_context::K() const {
360  if (!have_K()) {
361  GMM_ASSERT1(have_G() && have_pgt(), "Unable to compute K\n");
362  size_type P = pgt_->structure()->dim();
363  K_.base_resize(N(), P);
364  if (have_pgp()) {
365  pgt_->compute_K_matrix(*G_, pgp_->grad(ii_), K_);
366  } else {
367  PC.base_resize(pgt_->nb_points(), P);
368  pgt_->poly_vector_grad(xref(), PC);
369  pgt_->compute_K_matrix(*G_, PC, K_);
370  }
371  have_K_ = true;
372  }
373  return K_;
374  }
375 
376  const base_matrix& geotrans_interpolation_context::B() const {
377  if (!have_B()) {
378  const base_matrix &KK = K();
379  size_type P = pgt_->structure()->dim(), N_ = gmm::mat_nrows(KK);
380  B_.base_resize(N_, P);
381  if (!have_J_) compute_J();
382  GMM_ASSERT1(J__ != scalar_type(0), "Non invertible matrix");
383  if (P != N_) {
384  gmm::mult(KK, B_factors, B_);
385  } else {
386  switch(P) {
387  case 1: B_(0, 0) = scalar_type(1) / J__; break;
388  case 2:
389  {
390  auto it = &(*(KK.begin())); auto itB = &(*(B_.begin()));
391  *itB++ = it[3] / J__; *itB++ = -it[2] / J__;
392  *itB++ = -it[1] / J__; *itB = (*it) / J__;
393  } break;
394  case 3:
395  {
396  auto it = &(*(KK.begin())); auto itB = &(*(B_.begin()));
397  *itB++ /= J__; *itB++ /= J__; *itB++ /= J__;
398  *itB++ = (it[2]*it[7] - it[1]*it[8]) / J__;
399  *itB++ = (it[0]*it[8] - it[2]*it[6]) / J__;
400  *itB++ = (it[1]*it[6] - it[0]*it[7]) / J__;
401  *itB++ = (it[1]*it[5] - it[2]*it[4]) / J__;
402  *itB++ = (it[2]*it[3] - it[0]*it[5]) / J__;
403  *itB = (it[0]*it[4] - it[1]*it[3]) / J__;
404  } break;
405  default:
406  bgeot::lu_inverse(&(*(B_factors.begin())), ipvt, &(*(B_.begin())), P);
407  break;
408  }
409  }
410  have_B_ = true;
411  }
412  return B_;
413  }
414 
415  const base_matrix& geotrans_interpolation_context::B3() const {
416  if (!have_B3()) {
417  const base_matrix &BB = B();
418  size_type P=gmm::mat_ncols(BB), N_=gmm::mat_nrows(BB);
419  B3_.base_resize(N_*N_, P*P);
420  for (short_type i = 0; i < P; ++i)
421  for (short_type j = 0; j < P; ++j)
422  for (short_type k = 0; k < N_; ++k)
423  for (short_type l = 0; l < N_; ++l)
424  B3_(k + N_*l, i + P*j) = BB(k, i) * BB(l, j);
425  have_B3_ = true;
426  }
427  return B3_;
428  }
429 
430  const base_matrix& geotrans_interpolation_context::B32() const {
431  if (!have_B32()) {
432  const base_matrix &BB = B();
433  size_type P=gmm::mat_ncols(BB), N_=gmm::mat_nrows(BB);
434  B32_.base_resize(N_*N_, P);
435  if (!pgt()->is_linear()) {
436  base_matrix B2(P*P, P), Htau(N_, P*P);
437  if (have_pgp()) {
438  gmm::mult(G(), pgp_->hessian(ii_), Htau);
439  } else {
440  /* very inefficient of course... */
441  PC.base_resize(pgt()->nb_points(), P*P);
442  pgt()->poly_vector_hess(xref(), PC);
443  gmm::mult(G(), PC, Htau);
444  }
445  for (short_type i = 0; i < P; ++i)
446  for (short_type j = 0; j < P; ++j)
447  for (short_type k = 0; k < P; ++k)
448  for (short_type l = 0; l < N_; ++l)
449  B2(i + P*j, k) += Htau(l, i + P*j) * BB(l,k);
450  gmm::mult(B3(), B2, B32_);
451  } else gmm::clear(B32_);
452  have_B32_ = true;
453  }
454  return B32_;
455  }
456 
458  xref_ = P;
459  if (pgt_ && !pgt()->is_linear())
460  { have_K_ = have_B_ = have_B3_ = have_B32_ = have_J_ = false; }
461  xreal_.resize(0); ii_ = size_type(-1); pspt_ = 0;
462  }
463 
464 
466  const base_matrix &G) const {
467  size_type N = G.nrows(), k = nb_points();
468  base_node P(N); base_vector val(k);
469  poly_vector_val(pt, val);
470  base_matrix::const_iterator git = G.begin();
471  for (size_type l = 0; l < k; ++l) {
472  scalar_type a = val[l];
473  base_node::iterator pit = P.begin(), pite = P.end();
474  for (; pit != pite; ++git, ++pit) *pit += a * (*git);
475  }
476  return P;
477  }
478 
479  void geometric_trans::fill_standard_vertices() {
480  vertices_.resize(0);
481  for (size_type ip = 0; ip < nb_points(); ++ip) {
482  bool vertex = true;
483  for (size_type i = 0; i < cvr->points()[ip].size(); ++i)
484  if (gmm::abs(cvr->points()[ip][i]) > 1e-10
485  && gmm::abs(cvr->points()[ip][i]-1.0) > 1e-10
486  && gmm::abs(cvr->points()[ip][i]+1.0) > 1e-10)
487  { vertex = false; break; }
488  if (vertex) vertices_.push_back(ip);
489  }
490  dim_type dimension = dim();
491  if (dynamic_cast<const torus_geom_trans *>(this)) --dimension;
492  GMM_ASSERT1(vertices_.size() > dimension, "Internal error");
493  }
494 
495  /* ******************************************************************** */
496  /* Instantied geometric transformations. */
497  /* ******************************************************************** */
498 
499  template <class FUNC>
500  struct igeometric_trans : public geometric_trans {
501 
502  std::vector<FUNC> trans;
503  mutable std::vector<std::vector<FUNC>> grad_, hess_;
504  mutable bool grad_computed_ = false;
505  mutable bool hess_computed_ = false;
506 
507  void compute_grad_() const {
508  auto guard = getfem::omp_guard{};
509  if (grad_computed_) return;
510  size_type R = trans.size();
511  dim_type n = dim();
512  grad_.resize(R);
513  for (size_type i = 0; i < R; ++i) {
514  grad_[i].resize(n);
515  for (dim_type j = 0; j < n; ++j) {
516  grad_[i][j] = trans[i]; grad_[i][j].derivative(j);
517  }
518  }
519  grad_computed_ = true;
520  }
521 
522  void compute_hess_() const {
523  auto guard = getfem::omp_guard{};
524  if (hess_computed_) return;
525  size_type R = trans.size();
526  dim_type n = dim();
527  hess_.resize(R);
528  for (size_type i = 0; i < R; ++i) {
529  hess_[i].resize(n*n);
530  for (dim_type j = 0; j < n; ++j) {
531  for (dim_type k = 0; k < n; ++k) {
532  hess_[i][j+k*n] = trans[i];
533  hess_[i][j+k*n].derivative(j); hess_[i][j+k*n].derivative(k);
534  }
535  }
536  }
537  hess_computed_ = true;
538  }
539 
540  virtual void poly_vector_val(const base_node &pt, base_vector &val) const {
541  val.resize(nb_points());
542  for (size_type k = 0; k < nb_points(); ++k)
543  val[k] = to_scalar(trans[k].eval(pt.begin()));
544  }
545 
546  virtual void poly_vector_val(const base_node &pt,
547  const convex_ind_ct &ind_ct,
548  base_vector &val) const {
549  size_type nb_funcs=ind_ct.size();
550  val.resize(nb_funcs);
551  for (size_type k = 0; k < nb_funcs; ++k)
552  val[k] = to_scalar(trans[ind_ct[k]].eval(pt.begin()));
553  }
554 
555  virtual void poly_vector_grad(const base_node &pt, base_matrix &pc) const {
556  if (!grad_computed_) compute_grad_();
557  FUNC PP;
558  pc.base_resize(nb_points(),dim());
559  for (size_type i = 0; i < nb_points(); ++i)
560  for (dim_type n = 0; n < dim(); ++n)
561  pc(i, n) = to_scalar(grad_[i][n].eval(pt.begin()));
562  }
563 
564  virtual void poly_vector_grad(const base_node &pt,
565  const convex_ind_ct &ind_ct,
566  base_matrix &pc) const {
567  if (!grad_computed_) compute_grad_();
568  FUNC PP;
569  size_type nb_funcs=ind_ct.size();
570  pc.base_resize(nb_funcs,dim());
571  for (size_type i = 0; i < nb_funcs; ++i)
572  for (dim_type n = 0; n < dim(); ++n)
573  pc(i, n) = to_scalar(grad_[ind_ct[i]][n].eval(pt.begin()));
574  }
575 
576  virtual void poly_vector_hess(const base_node &pt, base_matrix &pc) const {
577  if (!hess_computed_) compute_hess_();
578  FUNC PP, QP;
579  pc.base_resize(nb_points(),dim()*dim());
580  for (size_type i = 0; i < nb_points(); ++i)
581  for (dim_type n = 0; n < dim(); ++n) {
582  for (dim_type m = 0; m <= n; ++m)
583  pc(i, n*dim()+m) = pc(i, m*dim()+n) =
584  to_scalar(hess_[i][m*dim()+n].eval(pt.begin()));
585  }
586  }
587 
588  };
589 
590  typedef igeometric_trans<base_poly> poly_geometric_trans;
591  typedef igeometric_trans<polynomial_composite> comppoly_geometric_trans;
592  typedef igeometric_trans<base_rational_fraction> fraction_geometric_trans;
593 
594  /* ******************************************************************** */
595  /* transformation on simplex. */
596  /* ******************************************************************** */
597 
598  struct simplex_trans_ : public poly_geometric_trans {
599  void calc_base_func(base_poly &p, size_type i, short_type K) const {
600  dim_type N = dim();
601  base_poly l0(N, 0), l1(N, 0);
602  power_index w(short_type(N+1));
603  l0.one(); l1.one(); p = l0;
604  for (short_type nn = 0; nn < N; ++nn) l0 -= base_poly(N, 1, nn);
605 
606  w[0] = K;
607  for (int nn = 1; nn <= N; ++nn) {
608  w[nn]=short_type(floor(0.5+(((cvr->points())[i])[nn-1]*double(K))));
609  w[0]=short_type(w[0]-w[nn]);
610  }
611 
612  for (short_type nn = 0; nn <= N; ++nn)
613  for (short_type j = 0; j < w[nn]; ++j)
614  if (nn == 0)
615  p *= (l0 * (scalar_type(K) / scalar_type(j+1)))
616  - (l1 * (scalar_type(j) / scalar_type(j+1)));
617  else
618  p *= (base_poly(N, 1, short_type(nn-1)) * (scalar_type(K) / scalar_type(j+1)))
619  - (l1 * (scalar_type(j) / scalar_type(j+1)));
620  }
621 
622  simplex_trans_(dim_type nc, short_type k) {
623  cvr = simplex_of_reference(nc, k);
624  size_type R = cvr->structure()->nb_points();
625  is_lin = (k == 1);
626  complexity_ = k;
627  trans.resize(R);
628  for (size_type r = 0; r < R; ++r) calc_base_func(trans[r], r, k);
629  fill_standard_vertices();
630  }
631  };
632 
633  static pgeometric_trans
634  PK_gt(gt_param_list &params,
635  std::vector<dal::pstatic_stored_object> &dependencies) {
636  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
637  << params.size() << " should be 2.");
638  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
639  "Bad type of parameters");
640  int n = int(::floor(params[0].num() + 0.01));
641  int k = int(::floor(params[1].num() + 0.01));
642  GMM_ASSERT1(n >= 0 && n < 100 && k >= 0 && k <= 150 &&
643  double(n) == params[0].num() && double(k) == params[1].num(),
644  "Bad parameters");
645  dependencies.push_back(simplex_of_reference(dim_type(n), dim_type(k)));
646  return std::make_shared<simplex_trans_>(dim_type(n), dim_type(k));
647  }
648 
649  /* ******************************************************************** */
650  /* direct product transformation */
651  /* ******************************************************************** */
652 
653  struct cv_pr_t_ : public poly_geometric_trans {
654  cv_pr_t_(const poly_geometric_trans *a, const poly_geometric_trans *b) {
655  cvr = convex_ref_product(a->convex_ref(), b->convex_ref());
656  is_lin = false;
657  complexity_ = a->complexity() * b->complexity();
658 
659  size_type n1 = a->nb_points(), n2 = b->nb_points();
660  trans.resize(n1 * n2);
661  for (size_type i1 = 0; i1 < n1; ++i1)
662  for (size_type i2 = 0; i2 < n2; ++i2) {
663  trans[i1 + i2 * n1] = a->trans[i1];
664  trans[i1 + i2 * n1].direct_product(b->trans[i2]);
665  }
666  for (size_type i2 = 0; i2 < b->nb_vertices(); ++i2)
667  for (size_type i1 = 0; i1 < a->nb_vertices(); ++i1)
668  vertices_.push_back(a->vertices()[i1] + b->vertices()[i2] * n1);
669  }
670  };
671 
672  static pgeometric_trans product_gt(gt_param_list &params,
673  std::vector<dal::pstatic_stored_object> &dependencies) {
674  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
675  << params.size() << " should be 2.");
676  GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
677  "Bad type of parameters");
678  pgeometric_trans a = params[0].method();
679  pgeometric_trans b = params[1].method();
680  dependencies.push_back(a); dependencies.push_back(b);
681  dependencies.push_back(convex_ref_product(a->convex_ref(),
682  b->convex_ref()));
683  const poly_geometric_trans *aa
684  = dynamic_cast<const poly_geometric_trans *>(a.get());
685  const poly_geometric_trans *bb
686  = dynamic_cast<const poly_geometric_trans *>(b.get());
687  GMM_ASSERT1(aa && bb, "The product of geometric transformations "
688  "is only defined for polynomial ones");
689  return std::make_shared<cv_pr_t_>(aa, bb);
690  }
691 
692  /* ******************************************************************** */
693  /* linear direct product transformation. */
694  /* ******************************************************************** */
695 
696  struct cv_pr_tl_ : public poly_geometric_trans {
697  cv_pr_tl_(const poly_geometric_trans *a, const poly_geometric_trans *b) {
698  GMM_ASSERT1(a->is_linear() && b->is_linear(),
699  "linear product of non-linear transformations");
700  cvr = convex_ref_product(a->convex_ref(), b->convex_ref());
701  is_lin = true;
702  complexity_ = std::max(a->complexity(), b->complexity());
703 
704  trans.resize(a->nb_points() * b->nb_points());
705  std::fill(trans.begin(), trans.end(), null_poly(dim()));
706 
707  std::stringstream name;
708  name << "GT_PK(" << int(dim()) << ",1)";
710  const poly_geometric_trans *pgt
711  = dynamic_cast<const poly_geometric_trans *>(pgt_.get());
712 
713  for (size_type i = 0; i <= dim(); ++i)
714  trans[cvr->structure()->ind_dir_points()[i]]
715  = pgt->trans[i];
716  for (size_type i2 = 0; i2 < b->nb_vertices(); ++i2)
717  for (size_type i1 = 0; i1 < a->nb_vertices(); ++i1)
718  vertices_.push_back(a->vertices()[i1]
719  + b->vertices()[i2] * a->nb_points());
720  }
721  };
722 
723  static pgeometric_trans linear_product_gt(gt_param_list &params,
724  std::vector<dal::pstatic_stored_object> &dependencies) {
725  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
726  << params.size() << " should be 2.");
727  GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
728  "Bad type of parameters");
729  pgeometric_trans a = params[0].method();
730  pgeometric_trans b = params[1].method();
731  dependencies.push_back(a); dependencies.push_back(b);
732  dependencies.push_back(convex_ref_product(a->convex_ref(),
733  b->convex_ref()));
734  const poly_geometric_trans *aa
735  = dynamic_cast<const poly_geometric_trans *>(a.get());
736  const poly_geometric_trans *bb
737  = dynamic_cast<const poly_geometric_trans *>(b.get());
738  GMM_ASSERT1(aa && bb, "The product of geometric transformations "
739  "is only defined for polynomial ones");
740  return std::make_shared<cv_pr_tl_>(aa, bb);
741  }
742 
743  /* ******************************************************************** */
744  /* parallelepiped transformation. */
745  /* ******************************************************************** */
746 
747  static pgeometric_trans QK_gt(gt_param_list &params,
748  std::vector<dal::pstatic_stored_object> &) {
749  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
750  << params.size() << " should be 2.");
751  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
752  "Bad type of parameters");
753  int n = int(::floor(params[0].num() + 0.01));
754  int k = int(::floor(params[1].num() + 0.01));
755  GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
756  double(n) == params[0].num() && double(k) == params[1].num(),
757  "Bad parameters");
758  std::stringstream name;
759  if (n == 1)
760  name << "GT_PK(1," << k << ")";
761  else
762  name << "GT_PRODUCT(GT_QK(" << n-1 << "," << k << "),GT_PK(1,"
763  << k << "))";
764  return geometric_trans_descriptor(name.str());
765  }
766 
767  static pgeometric_trans
768  prism_pk_gt(gt_param_list &params,
769  std::vector<dal::pstatic_stored_object> &) {
770  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
771  << params.size() << " should be 2.");
772  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
773  "Bad type of parameters");
774  int n = int(::floor(params[0].num() + 0.01));
775  int k = int(::floor(params[1].num() + 0.01));
776  GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
777  double(n) == params[0].num() && double(k) == params[1].num(),
778  "Bad parameters");
779  std::stringstream name;
780  name << "GT_PRODUCT(GT_PK(" << n-1 << "," << k << "),GT_PK(1,"
781  << k << "))";
782  return geometric_trans_descriptor(name.str());
783  }
784 
785  static pgeometric_trans
786  linear_qk(gt_param_list &params,
787  std::vector<dal::pstatic_stored_object> &) {
788  GMM_ASSERT1(params.size() == 1, "Bad number of parameters : "
789  << params.size() << " should be 1.");
790  GMM_ASSERT1(params[0].type() == 0, "Bad type of parameters");
791  int n = int(::floor(params[0].num() + 0.01));
792  return parallelepiped_linear_geotrans(n);
793  }
794 
795 
796  /* ******************************************************************** */
797  /* Incomplete Q2 geometric transformation for n=2 or 3. */
798  /* ******************************************************************** */
799  /* By Yao Koutsawa <yao.koutsawa@tudor.lu> 2012-12-10 */
800 
801  struct Q2_incomplete_trans_: public poly_geometric_trans {
802  Q2_incomplete_trans_(dim_type nc) {
803  cvr = Q2_incomplete_of_reference(nc);
804  size_type R = cvr->structure()->nb_points();
805  is_lin = false;
806  complexity_ = 2;
807  trans.resize(R);
808 
809  if (nc == 2) {
810  std::stringstream s
811  ( "1 - 2*x^2*y - 2*x*y^2 + 2*x^2 + 5*x*y + 2*y^2 - 3*x - 3*y;"
812  "4*(x^2*y - x^2 - x*y + x);"
813  "2*x*y*y - 2*x*x*y + 2*x*x - x*y - x;"
814  "4*(x*y*y - x*y - y*y + y);"
815  "4*(x*y - x*y*y);"
816  "2*x*x*y - 2*x*y*y - x*y + 2*y*y - y;"
817  "4*(x*y - x*x*y);"
818  "2*x*x*y + 2*x*y*y - 3*x*y;");
819 
820  for (int i = 0; i < 8; ++i)
821  trans[i] = read_base_poly(2, s);
822  } else {
823  std::stringstream s
824  ("1 + 2*x^2*y*z + 2*x*y^2*z + 2*x*y*z^2"
825  " - 2*x^2*y - 2*x^2*z - 2*x*y^2 - 2*y^2*z - 2*y*z^2 - 2*x*z^2 - 7*x*y*z"
826  " + 2*x^2 + 2*y^2 + 2*z^2 + 5*y*z + 5*x*z + 5*x*y - 3*x - 3*y - 3*z;"
827  "4*( - x^2*y*z + x*y*z + x^2*z - x*z + x^2*y - x*y - x^2 + x);"
828  "2*x^2*y*z - 2*x*y^2*z - 2*x*y*z^2"
829  " - 2*x^2*y - 2*x^2*z + 2*x*y^2 + 2*x*z^2 + 3*x*y*z + 2*x^2 - x*y - x*z - x;"
830  "4*( - x*y^2*z + x*y^2 + y^2*z + x*y*z - x*y - y^2 - y*z + y);"
831  "4*(x*y^2*z - x*y^2 - x*y*z + x*y);"
832  " - 2*x^2*y*z + 2*x*y^2*z - 2*x*y*z^2"
833  " + 2*x^2*y - 2*x*y^2 - 2*y^2*z + 2*y*z^2 + 3*x*y*z - x*y + 2*y^2 - y*z - y;"
834  "4*(x^2*y*z - x^2*y - x*y*z + x*y);"
835  " - 2*x^2*y*z - 2*x*y^2*z + 2*x*y*z^2 + 2*x^2*y + 2*x*y^2 + x*y*z - 3*x*y;"
836  "4*( - x*y*z^2 + x*z^2 + y*z^2 + x*y*z - x*z - y*z - z^2 + z);"
837  "4*(x*y*z^2 - x*y*z - x*z^2 + x*z);"
838  "4*(x*y*z^2 - x*y*z - y*z^2 + y*z);"
839  "4*( - x*y*z^2 + x*y*z);"
840  " - 2*x^2*y*z - 2*x*y^2*z + 2*x*y*z^2"
841  " + 2*x^2*z + 2*y^2*z - 2*x*z^2 - 2*y*z^2 + 3*x*y*z - x*z - y*z + 2*z^2 - z;"
842  "4*(x^2*y*z - x^2*z - x*y*z + x*z);"
843  " - 2*x^2*y*z + 2*x*y^2*z - 2*x*y*z^2 + 2*x^2*z + 2*x*z^2 + x*y*z - 3*x*z;"
844  "4*(x*y^2*z - y^2*z - x*y*z + y*z);"
845  "4*( - x*y^2*z + x*y*z);"
846  "2*x^2*y*z - 2*x*y^2*z - 2*x*y*z^2 + 2*y^2*z + 2*y*z^2 + x*y*z - 3*y*z;"
847  "4*( - x^2*y*z + x*y*z);"
848  "2*x^2*y*z + 2*x*y^2*z + 2*x*y*z^2 - 5*x*y*z;");
849 
850  for (int i = 0; i < 20; ++i)
851  trans[i] = read_base_poly(3, s);
852  }
853  fill_standard_vertices();
854  }
855  };
856 
857  static pgeometric_trans
858  Q2_incomplete_gt(gt_param_list& params,
859  std::vector<dal::pstatic_stored_object> &dependencies) {
860  GMM_ASSERT1(params.size() == 1, "Bad number of parameters : "
861  << params.size() << " should be 1.");
862  GMM_ASSERT1(params[0].type() == 0, "Bad type of parameters");
863  int n = int(::floor(params[0].num() + 0.01));
864  GMM_ASSERT1(n == 2 || n == 3, "Bad parameter, expected value 2 or 3");
865 
866  dependencies.push_back(Q2_incomplete_of_reference(dim_type(n)));
867  return std::make_shared<Q2_incomplete_trans_>(dim_type(n));
868  }
869 
870  pgeometric_trans Q2_incomplete_geotrans(dim_type nc) {
871  std::stringstream name;
872  name << "GT_Q2_INCOMPLETE(" << nc << ")";
873  return geometric_trans_descriptor(name.str());
874  }
875 
876  /* ******************************************************************** */
877  /* Pyramidal geometric transformation of order k=1 or 2. */
878  /* ******************************************************************** */
879 
880  struct pyramid_QK_trans_: public fraction_geometric_trans {
881  pyramid_QK_trans_(short_type k) {
882  cvr = pyramid_QK_of_reference(k);
883  size_type R = cvr->structure()->nb_points();
884  is_lin = false;
885  complexity_ = k;
886  trans.resize(R);
887 
888  if (k == 1) {
889  base_rational_fraction Q(read_base_poly(3, "x*y"), // Q = xy/(1-z)
890  read_base_poly(3, "1-z"));
891  trans[0] = (read_base_poly(3, "1-x-y-z") + Q)*0.25;
892  trans[1] = (read_base_poly(3, "1+x-y-z") - Q)*0.25;
893  trans[2] = (read_base_poly(3, "1-x+y-z") - Q)*0.25;
894  trans[3] = (read_base_poly(3, "1+x+y-z") + Q)*0.25;
895  trans[4] = read_base_poly(3, "z");
896  } else if (k == 2) {
897  base_poly xi0 = read_base_poly(3, "(1-z-x)*0.5");
898  base_poly xi1 = read_base_poly(3, "(1-z-y)*0.5");
899  base_poly xi2 = read_base_poly(3, "(1-z+x)*0.5");
900  base_poly xi3 = read_base_poly(3, "(1-z+y)*0.5");
901  base_poly x = read_base_poly(3, "x");
902  base_poly y = read_base_poly(3, "y");
903  base_poly z = read_base_poly(3, "z");
904  base_poly ones = read_base_poly(3, "1");
905  base_poly un_z = read_base_poly(3, "1-z");
906  base_rational_fraction Q(read_base_poly(3, "1"), un_z); // Q = 1/(1-z)
907  trans[ 0] = Q*Q*xi0*xi1*(x*y-z*un_z);
908  trans[ 1] = Q*Q*xi0*xi1*xi2*(xi1*2.-un_z)*4.;
909  trans[ 2] = Q*Q*xi1*xi2*(-x*y-z*un_z);
910  trans[ 3] = Q*Q*xi3*xi0*xi1*(xi0*2.-un_z)*4.;
911  trans[ 4] = Q*Q*xi0*xi1*xi2*xi3*16.;
912  trans[ 5] = Q*Q*xi1*xi2*xi3*(xi2*2.-un_z)*4.;
913  trans[ 6] = Q*Q*xi3*xi0*(-x*y-z*un_z);
914  trans[ 7] = Q*Q*xi2*xi3*xi0*(xi3*2.-un_z)*4.;
915  trans[ 8] = Q*Q*xi2*xi3*(x*y-z*un_z);
916  trans[ 9] = Q*z*xi0*xi1*4.;
917  trans[10] = Q*z*xi1*xi2*4.;
918  trans[11] = Q*z*xi3*xi0*4.;
919  trans[12] = Q*z*xi2*xi3*4.;
920  trans[13] = read_base_poly(3, "z*(2*z-1)");
921  }
922  fill_standard_vertices();
923  }
924  };
925 
926  static pgeometric_trans
927  pyramid_QK_gt(gt_param_list& params,
928  std::vector<dal::pstatic_stored_object> &deps) {
929  GMM_ASSERT1(params.size() == 1, "Bad number of parameters : "
930  << params.size() << " should be 1.");
931  GMM_ASSERT1(params[0].type() == 0, "Bad type of parameters");
932  int k = int(::floor(params[0].num() + 0.01));
933 
934  deps.push_back(pyramid_QK_of_reference(dim_type(k)));
935  return std::make_shared<pyramid_QK_trans_>(dim_type(k));
936  }
937 
938  pgeometric_trans pyramid_QK_geotrans(short_type k) {
939  static short_type k_ = -1;
940  static pgeometric_trans pgt = 0;
941  if (k != k_) {
942  std::stringstream name;
943  name << "GT_PYRAMID(" << k << ")";
944  pgt = geometric_trans_descriptor(name.str());
945  }
946  return pgt;
947  }
948 
949  /* ******************************************************************** */
950  /* Incomplete quadratic pyramidal geometric transformation. */
951  /* ******************************************************************** */
952 
953  struct pyramid_Q2_incomplete_trans_: public fraction_geometric_trans {
954  pyramid_Q2_incomplete_trans_() {
956  size_type R = cvr->structure()->nb_points();
957  is_lin = false;
958  complexity_ = 2;
959  trans.resize(R);
960 
961  base_poly xy = read_base_poly(3, "x*y");
962  base_poly z = read_base_poly(3, "z");
963 
964  base_poly p00m = read_base_poly(3, "1-z");
965 
966  base_poly pmmm = read_base_poly(3, "1-x-y-z");
967  base_poly ppmm = read_base_poly(3, "1+x-y-z");
968  base_poly pmpm = read_base_poly(3, "1-x+y-z");
969  base_poly pppm = read_base_poly(3, "1+x+y-z");
970 
971  base_poly mmm0_ = read_base_poly(3, "-1-x-y")*0.25;
972  base_poly mpm0_ = read_base_poly(3, "-1+x-y")*0.25;
973  base_poly mmp0_ = read_base_poly(3, "-1-x+y")*0.25;
974  base_poly mpp0_ = read_base_poly(3, "-1+x+y")*0.25;
975 
976  base_poly pp0m = read_base_poly(3, "1+x-z");
977  base_poly pm0m = read_base_poly(3, "1-x-z");
978  base_poly p0mm = read_base_poly(3, "1-y-z");
979  base_poly p0pm = read_base_poly(3, "1+y-z");
980 
981  trans[ 0] = mmm0_ * pmmm + base_rational_fraction(mmm0_ * xy, p00m); // N5 (Bedrosian, 1992)
982  trans[ 1] = base_rational_fraction(pp0m * pm0m * p0mm * 0.5, p00m); // N6
983  trans[ 2] = mpm0_ * ppmm - base_rational_fraction(mpm0_ * xy, p00m); // N7
984  trans[ 3] = base_rational_fraction(p0pm * p0mm * pm0m * 0.5, p00m); // N4
985  trans[ 4] = base_rational_fraction(p0pm * p0mm * pp0m * 0.5, p00m); // N8
986  trans[ 5] = mmp0_ * pmpm - base_rational_fraction(mmp0_ * xy, p00m); // N3
987  trans[ 6] = base_rational_fraction(pp0m * pm0m * p0pm * 0.5, p00m); // N2
988  trans[ 7] = mpp0_ * pppm + base_rational_fraction(mpp0_ * xy, p00m); // N1
989  trans[ 8] = base_rational_fraction(pm0m * p0mm * z, p00m); // N11
990  trans[ 9] = base_rational_fraction(pp0m * p0mm * z, p00m); // N12
991  trans[10] = base_rational_fraction(pm0m * p0pm * z, p00m); // N10
992  trans[11] = base_rational_fraction(pp0m * p0pm * z, p00m); // N9
993  trans[12] = read_base_poly(3, "2*z^2-z"); // N13
994 
995  fill_standard_vertices();
996  }
997  };
998 
999  static pgeometric_trans
1000  pyramid_Q2_incomplete_gt(gt_param_list& params,
1001  std::vector<dal::pstatic_stored_object> &deps) {
1002  GMM_ASSERT1(params.size() == 0, "Bad number of parameters : "
1003  << params.size() << " should be 0.");
1004 
1005  deps.push_back(pyramid_Q2_incomplete_of_reference());
1006  return std::make_shared<pyramid_Q2_incomplete_trans_>();
1007  }
1008 
1009  pgeometric_trans pyramid_Q2_incomplete_geotrans() {
1010  static pgeometric_trans pgt = 0;
1011  if (!pgt)
1012  pgt = geometric_trans_descriptor("GT_PYRAMID_Q2_INCOMPLETE");
1013  return pgt;
1014  }
1015 
1016  /* ******************************************************************** */
1017  /* Incomplete quadratic prism geometric transformation. */
1018  /* ******************************************************************** */
1019 
1020  struct prism_incomplete_P2_trans_: public poly_geometric_trans {
1021  prism_incomplete_P2_trans_() {
1023  size_type R = cvr->structure()->nb_points();
1024  is_lin = false;
1025  complexity_ = 2;
1026  trans.resize(R);
1027 
1028  std::stringstream s
1029  ( "-2*y*z^2-2*x*z^2+2*z^2-2*y^2*z-4*x*y*z+5*y*z-2*x^2*z+5*x*z"
1030  "-3*z+2*y^2+4*x*y-3*y+2*x^2-3*x+1;"
1031  "4*(x*y*z+x^2*z-x*z-x*y-x^2+x);"
1032  "2*x*z^2-2*x^2*z-x*z+2*x^2-x;"
1033  "4*(y^2*z+x*y*z-y*z-y^2-x*y+y);"
1034  "4*(x*y-x*y*z);"
1035  "2*y*z^2-2*y^2*z-y*z+2*y^2-y;"
1036  "4*(y*z^2+x*z^2-z^2-y*z-x*z+z);"
1037  "4*(x*z-x*z^2);"
1038  "4*(y*z-y*z^2);"
1039  "-2*y*z^2-2*x*z^2+2*z^2+2*y^2*z+4*x*y*z-y*z+2*x^2*z-x*z-z;"
1040  "4*(-x*y*z-x^2*z+x*z);"
1041  "2*x*z^2+2*x^2*z-3*x*z;"
1042  "4*(-y^2*z-x*y*z+y*z);"
1043  "4*x*y*z;"
1044  "2*y*z^2+2*y^2*z-3*y*z;");
1045 
1046  for (int i = 0; i < 15; ++i)
1047  trans[i] = read_base_poly(3, s);
1048 
1049  fill_standard_vertices();
1050  }
1051  };
1052 
1053  static pgeometric_trans
1054  prism_incomplete_P2_gt(gt_param_list& params,
1055  std::vector<dal::pstatic_stored_object> &deps) {
1056  GMM_ASSERT1(params.size() == 0, "Bad number of parameters : "
1057  << params.size() << " should be 0.");
1058 
1059  deps.push_back(prism_incomplete_P2_of_reference());
1060  return std::make_shared<prism_incomplete_P2_trans_>();
1061  }
1062 
1063  pgeometric_trans prism_incomplete_P2_geotrans() {
1064  static pgeometric_trans pgt = 0;
1065  if (!pgt)
1066  pgt = geometric_trans_descriptor("GT_PRISM_INCOMPLETE_P2");
1067  return pgt;
1068  }
1069 
1070  /* ******************************************************************** */
1071  /* Misc function. */
1072  /* ******************************************************************** */
1073 
1074  /* norm of returned vector is the ratio between the face surface on
1075  the reference element and the face surface on the real element.
1076  IT IS NOT UNITARY
1077 
1078  pt is the position of the evaluation point on the reference element
1079  */
1081  size_type face) {
1082  GMM_ASSERT1(c.G().ncols() == c.pgt()->nb_points(), "dimensions mismatch");
1083  base_small_vector un(c.N());
1084  gmm::mult(c.B(), c.pgt()->normals()[face], un);
1085  return un;
1086  }
1087 
1088  /*
1089  return the local basis (i.e. the normal in the first column, and the
1090  tangent vectors in the other columns
1091  */
1092  base_matrix
1094  size_type face) {
1095  GMM_ASSERT1(c.G().ncols() == c.pgt()->nb_points(), "dimensions mismatch");
1096  base_small_vector up = c.pgt()->normals()[face];
1097  size_type P = c.pgt()->structure()->dim();
1098 
1099  base_matrix baseP(P, P);
1100  gmm::copy(gmm::identity_matrix(), baseP);
1101  size_type i0 = 0;
1102  for (size_type i=1; i < P; ++i)
1103  if (gmm::abs(up[i])>gmm::abs(up[i0])) i0=i;
1104  if (i0) gmm::copy(gmm::mat_col(baseP, 0), gmm::mat_col(baseP, i0));
1105  gmm::copy(up, gmm::mat_col(baseP, 0));
1106 
1107  base_matrix baseN(c.N(), P);
1108  gmm::mult(c.B(), baseP, baseN);
1109 
1110  /* Modified Gram-Schmidt */
1111  for (size_type k=0; k < P; ++k) {
1112  for (size_type l=0; l < k; ++l) {
1113  gmm::add(gmm::scaled(gmm::mat_col(baseN,l),
1114  -gmm::vect_sp(gmm::mat_col(baseN,l),
1115  gmm::mat_col(baseN,k))),
1116  gmm::mat_col(baseN,k));
1117  }
1118  gmm::scale(gmm::mat_col(baseN,k),
1119  1./gmm::vect_norm2(gmm::mat_col(baseN,k)));
1120  }
1121  /* TODO: for cases where P < N, complete the basis */
1122 
1123  /* Ensure that the baseN is direct */
1124  if (c.N() == P && c.N()>1 && gmm::lu_det(baseN) < 0) {
1125  gmm::scale(gmm::mat_col(baseN,1),-1.);
1126  }
1127  return baseN;
1128  }
1129 
1130 
1131 
1132 
1133  /* ******************************************************************** */
1134  /* Naming system */
1135  /* ******************************************************************** */
1136 
1137  struct geometric_trans_naming_system
1138  : public dal::naming_system<geometric_trans> {
1139  geometric_trans_naming_system() :
1141  add_suffix("PK", PK_gt);
1142  add_suffix("QK", QK_gt);
1143  add_suffix("PRISM_PK", prism_pk_gt);
1144  add_suffix("PRISM", prism_pk_gt);
1145  add_suffix("PRODUCT", product_gt);
1146  add_suffix("LINEAR_PRODUCT", linear_product_gt);
1147  add_suffix("LINEAR_QK", linear_qk);
1148  add_suffix("Q2_INCOMPLETE", Q2_incomplete_gt);
1149  add_suffix("PYRAMID_QK", pyramid_QK_gt);
1150  add_suffix("PYRAMID", pyramid_QK_gt);
1151  add_suffix("PYRAMID_Q2_INCOMPLETE", pyramid_Q2_incomplete_gt);
1152  add_suffix("PRISM_INCOMPLETE_P2", prism_incomplete_P2_gt);
1153  }
1154  };
1155 
1156  void add_geometric_trans_name
1157  (std::string name, dal::naming_system<geometric_trans>::pfunction f) {
1159  f);
1160  }
1161 
1163  size_type i=0;
1165  }
1166 
1169  const torus_geom_trans *pgt_torus = dynamic_cast<const torus_geom_trans *>(p.get());
1170  if (pgt_torus) return instance.shorter_name_of_method(pgt_torus->get_original_transformation());
1171  return instance.shorter_name_of_method(p);
1172  }
1173 
1174  /* Fonctions pour la ref. directe. */
1175 
1176  pgeometric_trans simplex_geotrans(size_type n, short_type k) {
1177  static pgeometric_trans pgt = 0;
1178  static size_type d = size_type(-2);
1179  static short_type r = short_type(-2);
1180  if (d != n || r != k) {
1181  std::stringstream name;
1182  name << "GT_PK(" << n << "," << k << ")";
1183  pgt = geometric_trans_descriptor(name.str());
1184  d = n; r = k;
1185  }
1186  return pgt;
1187  }
1188 
1189  pgeometric_trans parallelepiped_geotrans(size_type n, short_type k) {
1190  static pgeometric_trans pgt = 0;
1191  static size_type d = size_type(-2);
1192  static short_type r = short_type(-2);
1193  if (d != n || r != k) {
1194  std::stringstream name;
1195  name << "GT_QK(" << n << "," << k << ")";
1196  pgt = geometric_trans_descriptor(name.str());
1197  d = n; r = k;
1198  }
1199  return pgt;
1200  }
1201 
1202  static std::string name_of_linear_qk_trans(size_type dim) {
1203  switch (dim) {
1204  case 1: return "GT_PK(1,1)";
1205  default: return std::string("GT_LINEAR_PRODUCT(")
1206  + name_of_linear_qk_trans(dim-1)
1207  + std::string(",GT_PK(1,1))");
1208  }
1209  }
1210 
1211  pgeometric_trans parallelepiped_linear_geotrans(size_type n) {
1212  static pgeometric_trans pgt = 0;
1213  static size_type d = size_type(-2);
1214  if (d != n) {
1215  std::stringstream name(name_of_linear_qk_trans(n));
1216  pgt = geometric_trans_descriptor(name.str());
1217  d = n;
1218  }
1219  return pgt;
1220  }
1221 
1222  pgeometric_trans prism_linear_geotrans(size_type n) {
1223  static pgeometric_trans pgt = 0;
1224  static size_type d = size_type(-2);
1225  if (d != n) {
1226  std::stringstream name;
1227  name << "GT_LINEAR_PRODUCT(GT_PK(" << (n-1) << ", 1), GT_PK(1,1))";
1228  pgt = geometric_trans_descriptor(name.str());
1229  d = n;
1230  }
1231  return pgt;
1232  }
1233 
1234  pgeometric_trans linear_product_geotrans(pgeometric_trans pg1,
1235  pgeometric_trans pg2) {
1236  std::stringstream name;
1237  name << "GT_LINEAR_PRODUCT(" << name_of_geometric_trans(pg1) << ","
1238  << name_of_geometric_trans(pg2) << ")";
1239  return geometric_trans_descriptor(name.str());
1240  }
1241 
1242  pgeometric_trans prism_geotrans(size_type n, short_type k) {
1243  static pgeometric_trans pgt = 0;
1244  static size_type d = size_type(-2);
1245  static short_type r = short_type(-2);
1246  if (d != n || r != k) {
1247  std::stringstream name;
1248  name << "GT_PRISM(" << n << "," << k << ")";
1249  pgt = geometric_trans_descriptor(name.str());
1250  d = n; r = k;
1251  }
1252  return pgt;
1253  }
1254 
1255  pgeometric_trans product_geotrans(pgeometric_trans pg1,
1256  pgeometric_trans pg2) {
1257  static pgeometric_trans pgt = 0;
1258  static pgeometric_trans pg1_ = 0;
1259  static pgeometric_trans pg2_ = 0;
1260  if (pg1 != pg1_ || pg2 != pg2_) {
1261  std::stringstream name;
1262  name << "GT_PRODUCT(" << name_of_geometric_trans(pg1) << ","
1263  << name_of_geometric_trans(pg2) << ")";
1264  pgt = geometric_trans_descriptor(name.str());
1265  pg1_ = pg1; pg2_ = pg2;
1266  }
1267  return pgt;
1268  }
1269 
1270  /* ********************************************************************* */
1271  /* Precomputation on geometric transformations. */
1272  /* ********************************************************************* */
1273 
1274  DAL_DOUBLE_KEY(pre_geot_key_, pgeometric_trans, pstored_point_tab);
1275 
1276  geotrans_precomp_::geotrans_precomp_(pgeometric_trans pg,
1277  pstored_point_tab ps)
1278  : pgt(pg), pspt(ps)
1279  { DAL_STORED_OBJECT_DEBUG_CREATED(this, "Geotrans precomp"); }
1280 
1281  void geotrans_precomp_::init_val() const {
1282  c.clear();
1283  c.resize(pspt->size(), base_vector(pgt->nb_points()));
1284  for (size_type j = 0; j < pspt->size(); ++j)
1285  pgt->poly_vector_val((*pspt)[j], c[j]);
1286  }
1287 
1288  void geotrans_precomp_::init_grad() const {
1289  dim_type N = pgt->dim();
1290  pc.clear();
1291  pc.resize(pspt->size(), base_matrix(pgt->nb_points() , N));
1292  for (size_type j = 0; j < pspt->size(); ++j)
1293  pgt->poly_vector_grad((*pspt)[j], pc[j]);
1294  }
1295 
1296  void geotrans_precomp_::init_hess() const {
1297  base_poly P, Q;
1298  dim_type N = pgt->structure()->dim();
1299  hpc.clear();
1300  hpc.resize(pspt->size(), base_matrix(pgt->nb_points(), gmm::sqr(N)));
1301  for (size_type j = 0; j < pspt->size(); ++j)
1302  pgt->poly_vector_hess((*pspt)[j], hpc[j]);
1303  }
1304 
1306  const base_matrix &G) const {
1307  if (c.empty()) init_val();
1308  size_type N = G.nrows(), k = pgt->nb_points();
1309  base_node P(N);
1310  base_matrix::const_iterator git = G.begin();
1311  for (size_type l = 0; l < k; ++l) {
1312  scalar_type a = c[i][l];
1313  base_node::iterator pit = P.begin(), pite = P.end();
1314  for (; pit != pite; ++git, ++pit) *pit += a * (*git);
1315  }
1316  return P;
1317  }
1318 
1319  pgeotrans_precomp geotrans_precomp(pgeometric_trans pg,
1320  pstored_point_tab pspt,
1321  dal::pstatic_stored_object dep) {
1322  dal::pstatic_stored_object_key pk= std::make_shared<pre_geot_key_>(pg,pspt);
1323  dal::pstatic_stored_object o = dal::search_stored_object(pk);
1324  if (o) return std::dynamic_pointer_cast<const geotrans_precomp_>(o);
1325  pgeotrans_precomp p = std::make_shared<geotrans_precomp_>(pg, pspt);
1326  dal::add_stored_object(pk, p, pg, pspt, dal::AUTODELETE_STATIC_OBJECT);
1327  if (dep) dal::add_dependency(p, dep);
1328  return p;
1329  }
1330 
1331  void delete_geotrans_precomp(pgeotrans_precomp pgp)
1332  { dal::del_stored_object(pgp); }
1333 
1334 } /* end of namespace bgeot. */
1335 
base_matrix compute_local_basis(const geotrans_interpolation_context &c, size_type face)
return the local basis (i.e.
const base_matrix * G_
transformed point
Geometric transformations on convexes.
virtual void compute_K_matrix(const base_matrix &G, const base_matrix &pc, base_matrix &K) const
compute K matrix from multiplication of G with gradient
scalar_type J_
index of current point in the pgp
base_poly read_base_poly(short_type n, std::istream &f)
read a base_poly on the stream ist.
Definition: bgeot_poly.cc:210
pconvex_ref pyramid_QK_of_reference(dim_type k)
pyramidal element of reference of degree k (k = 1 or 2 only)
Handle composite polynomials.
Description of a geometric transformation between a reference element and a real element.
pgeometric_trans pgt_
see documentation (getfem kernel doc) for more details
void one()
Makes P = 1.
Definition: bgeot_poly.h:242
the geotrans_interpolation_context structure is passed as the argument of geometric transformation in...
void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored)
Delete an object and the object which depend on it.
pgeometric_trans geometric_trans_descriptor(std::string name)
Get the geometric transformation from its string name.
pconvex_ref Q2_incomplete_of_reference(dim_type nc)
incomplete Q2 quadrilateral/hexahedral of reference of dimension d = 2 or 3
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...
pstatic_stored_object search_stored_object(pstatic_stored_object_key k)
Gives a pointer to an object from a key pointer.
const base_node & cv_center() const
coordinates of the center of the real convex.
const base_node & xreal() const
coordinates of the current point, in the real convex.
pconvex_ref convex_ref_product(pconvex_ref a, pconvex_ref b)
tensorial product of two convex ref.
static T & instance()
Instance from the current thread.
Associate a name to a method descriptor and store method descriptors.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
precomputed geometric transformation operations use this for repetitive evaluation of a geometric tra...
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
Vector of integer (16 bits type) which represent the powers of a monomial.
Definition: bgeot_poly.h:64
A simple singleton implementation.
base_node cv_center_
pointer to the matrix of real nodes of the convex
a balanced tree stored in a dal::dynamic_array
size_type ii_
if pgp != 0, it is the same as pgp&#39;s one
pconvex_ref prism_incomplete_P2_of_reference()
incomplete quadratic prism element of reference (15-node)
void add_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
Add a dependency, object o1 will depend on object o2.
base_matrix K_
real center of convex (average of columns of G)
short_type dim() const
Gives the dimension (number of variables)
Definition: bgeot_poly.h:199
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:79
std::string name_of_geometric_trans(pgeometric_trans p)
Get the string name of a geometric transformation.
const base_node & xref() const
coordinates of the current point, in the reference convex.
base_small_vector compute_normal(const geotrans_interpolation_context &c, size_type face)
norm of returned vector is the ratio between the face surface on the real element and the face surfac...
pconvex_ref pyramid_Q2_incomplete_of_reference()
incomplete quadratic pyramidal element of reference (13-node)
void transform(const CONT &G, stored_point_tab &pt_tab) const
Apply the geometric transformation from the reference convex to the convex whose vertices are stored ...
const base_matrix & G() const
matrix whose columns are the vertices of the convex
const base_matrix & K() const
See getfem kernel doc for these matrices.
Basic Geometric Tools.
void set_xref(const base_node &P)
change the current point (coordinates given in the reference convex)
An adaptor that adapts a two dimensional geometric_trans to include radial dimension.
Definition: bgeot_torus.h:48
pconvex_ref simplex_of_reference(dim_type nc, short_type K)
returns a simplex of reference of dimension nc and degree k
Provides mesh of torus.
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation