GetFEM  5.5
bgeot_geometric_trans.cc
1 /*===========================================================================
2 
3  Copyright (C) 2000-2026 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
21 
22 #include "getfem/dal_singleton.h"
23 #include "getfem/dal_tree_sorted.h"
26 #include "getfem/bgeot_torus.h"
27 
28 namespace bgeot {
29 
30  std::vector<scalar_type>& __aux1(){
31  THREAD_SAFE_STATIC std::vector<scalar_type> v;
32  return v;
33  }
34 
35  std::vector<scalar_type>& __aux2(){
36  THREAD_SAFE_STATIC std::vector<scalar_type> v;
37  return v;
38  }
39 
40  std::vector<scalar_type>& __aux3(){
41  THREAD_SAFE_STATIC std::vector<scalar_type> v;
42  return v;
43  }
44 
45  std::vector<long>& __ipvt_aux(){
46  THREAD_SAFE_STATIC std::vector<long> vi;
47  return vi;
48  }
49 
50  // Optimized matrix mult for small matrices. To be verified.
51  // Multiply the matrix A of size MxN by B of size NxP in C of size MxP
52  void mat_mult(const scalar_type *A, const scalar_type *B, scalar_type *C,
53  size_type M, size_type N, size_type P) {
54  if (N != 0) {
55  auto itC = C; auto itB = B;
56  for (size_type j = 0; j < P; ++j, itB += N)
57  for (size_type i = 0; i < M; ++i, ++itC) {
58  auto itA = A+i, itB1 = itB;
59  *itC = (*itA) * (*itB1);
60  for (size_type k = 1; k < N; ++k)
61  { itA += M; ++itB1; *itC += (*itA) * (*itB1); }
62  }
63  } else std::fill(C, C+M*P, scalar_type(0));
64  }
65 
66  // Optimized matrix mult for small matrices.
67  // Multiply the matrix A of size MxN by the transpose of B of size PxN
68  // in C of size MxP
69  void mat_tmult(const scalar_type *A, const scalar_type *B, scalar_type *C,
70  size_type M, size_type N, size_type P) {
71  auto itC = C;
72  switch (N) {
73  case 0 : std::fill(C, C+M*P, scalar_type(0)); break;
74  case 1 :
75  for (size_type j = 0; j < P; ++j)
76  for (size_type i = 0; i < M; ++i, ++itC) {
77  auto itA = A+i, itB = B+j;
78  *itC = (*itA) * (*itB);
79  }
80  break;
81  case 2 :
82  for (size_type j = 0; j < P; ++j)
83  for (size_type i = 0; i < M; ++i, ++itC) {
84  auto itA = A+i, itB = B+j;
85  *itC = (*itA) * (*itB);
86  itA += M; itB += P; *itC += (*itA) * (*itB);
87  }
88  break;
89  case 3 :
90  for (size_type j = 0; j < P; ++j)
91  for (size_type i = 0; i < M; ++i, ++itC) {
92  auto itA = A+i, itB = B+j;
93  *itC = (*itA) * (*itB);
94  itA += M; itB += P; *itC += (*itA) * (*itB);
95  itA += M; itB += P; *itC += (*itA) * (*itB);
96  }
97  break;
98  default :
99  for (size_type j = 0; j < P; ++j)
100  for (size_type i = 0; i < M; ++i, ++itC) {
101  auto itA = A+i, itB = B+j;
102  *itC = (*itA) * (*itB);
103  for (size_type k = 1; k < N; ++k)
104  { itA += M; itB += P; *itC += (*itA) * (*itB); }
105  }
106  }
107  }
108 
109 
110 
111 
112  // Optimized lu_factor for small square matrices
113  size_type lu_factor(scalar_type *A, std::vector<long> &ipvt,
114  size_type N) {
115  size_type info(0), i, j, jp, N_1 = N-1;
116 
117  if (N) {
118  for (j = 0; j < N_1; ++j) {
119  auto it = A + (j*(N+1));
120  scalar_type max = gmm::abs(*it); jp = j;
121  for (i = j+1; i < N; ++i) {
122  scalar_type ap = gmm::abs(*(++it));
123  if (ap > max) { jp = i; max = ap; }
124  }
125  ipvt[j] = long(jp + 1);
126 
127  if (max == scalar_type(0)) { info = j + 1; break; }
128  if (jp != j) {
129  auto it1 = A+jp, it2 = A+j;
130  for (i = 0; i < N; ++i, it1+=N, it2+=N) std::swap(*it1, *it2);
131  }
132  it = A + (j*(N+1)); max = *it++;
133  for (i = j+1; i < N; ++i) *it++ /= max;
134  auto it22 = A + (j*N + j+1), it11 = it22;
135  auto it3 = A + ((j+1)*N+j);
136  for (size_type l = j+1; l < N; ++l) {
137  it11 += N;
138  auto it1 = it11, it2 = it22;
139  scalar_type a = *it3; it3 += N;
140  for (size_type k = j+1; k < N; ++k) *it1++ -= *it2++ * a;
141  }
142 
143  }
144  ipvt[N-1] = long(N);
145  }
146  return info;
147  }
148 
149  static void lower_tri_solve(const scalar_type *T, scalar_type *x, int N,
150  bool is_unit) {
151  scalar_type x_j;
152  for (int j = 0; j < N; ++j) {
153  auto itc = T + j*N, it = itc+(j+1), ite = itc+N;
154  auto itx = x + j;
155  if (!is_unit) *itx /= itc[j];
156  x_j = *itx++;
157  for (; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
158  }
159  }
160 
161  static void upper_tri_solve(const scalar_type *T, scalar_type *x, int N,
162  bool is_unit) {
163  scalar_type x_j;
164  for (int j = N - 1; j >= 0; --j) {
165  auto itc = T + j*N, it = itc, ite = itc+j;
166  auto itx = x;
167  if (!is_unit) x[j] /= itc[j];
168  for (x_j = x[j]; it != ite ; ++it, ++itx) *itx -= x_j * (*it);
169  }
170  }
171 
172  static void lu_solve(const scalar_type *LU, const std::vector<long> &ipvt,
173  scalar_type *x, scalar_type *b, int N) {
174  std::copy(b, b+N, x);
175  for(int i = 0; i < N; ++i)
176  { long perm = ipvt[i]-1; if(i != perm) std::swap(x[i], x[perm]); }
177  bgeot::lower_tri_solve(LU, x, N, true);
178  bgeot::upper_tri_solve(LU, x, N, false);
179  }
180 
181  scalar_type lu_det(const scalar_type *LU, const std::vector<long> &ipvt,
182  size_type N) {
183  scalar_type det(1);
184  for (size_type j = 0; j < N; ++j) det *= *(LU+j*(N+1));
185  for(long i = 0; i < long(N); ++i) if (i != ipvt[i]-1) { det = -det; }
186  return det;
187  }
188 
189  scalar_type lu_det(const scalar_type *A, size_type N) {
190  switch (N) {
191  case 1: return *A;
192  case 2: return (*A) * (A[3]) - (A[1]) * (A[2]);
193  case 3:
194  {
195  scalar_type a0 = A[4]*A[8] - A[5]*A[7], a3 = A[5]*A[6] - A[3]*A[8];
196  scalar_type a6 = A[3]*A[7] - A[4]*A[6];
197  return A[0] * a0 + A[1] * a3 + A[2] * a6;
198  }
199  default:
200  {
201  size_type NN = N*N;
202  if (__aux1().size() < NN) __aux1().resize(N*N);
203  std::copy(A, A+NN, __aux1().begin());
204  __ipvt_aux().resize(N);
205  lu_factor(&(*(__aux1().begin())), __ipvt_aux(), N);
206  return lu_det(&(*(__aux1().begin())), __ipvt_aux(), N);
207  }
208  }
209  }
210 
211  void lu_inverse(const scalar_type *LU, const std::vector<long> &ipvt,
212  scalar_type *A, size_type N) {
213  __aux2().resize(N); gmm::clear(__aux2());
214  __aux3().resize(N);
215  for(size_type i = 0; i < N; ++i) {
216  __aux2()[i] = scalar_type(1);
217  bgeot::lu_solve(LU, ipvt, A+i*N, &(*(__aux2().begin())), int(N));
218  __aux2()[i] = scalar_type(0);
219  }
220  }
221 
222  scalar_type lu_inverse(scalar_type *A, size_type N, bool doassert) {
223  switch (N) {
224  case 1:
225  {
226  scalar_type det = *A;
227  GMM_ASSERT1(!doassert || det != scalar_type(0), "Non invertible matrix");
228  *A = scalar_type(1)/det;
229  return det;
230  }
231  case 2:
232  {
233  scalar_type a = *A, b = A[2], c = A[1], d = A[3];
234  scalar_type det = a * d - b * c;
235  GMM_ASSERT1(!doassert || det != scalar_type(0), "Non invertible matrix");
236  *A++ = d/det; *A++ /= -det; *A++ /= -det; *A = a/det;
237  return det;
238  }
239  case 3:
240  {
241  scalar_type a0 = A[4]*A[8] - A[5]*A[7], a1 = A[5]*A[6] - A[3]*A[8];
242  scalar_type a2 = A[3]*A[7] - A[4]*A[6];
243  scalar_type det = A[0] * a0 + A[1] * a1 + A[2] * a2;
244  GMM_ASSERT1(!doassert || det != scalar_type(0), "Non invertible matrix");
245  scalar_type a3 = (A[2]*A[7] - A[1]*A[8]), a6 = (A[1]*A[5] - A[2]*A[4]);
246  scalar_type a4 = (A[0]*A[8] - A[2]*A[6]), a7 = (A[2]*A[3] - A[0]*A[5]);
247  scalar_type a5 = (A[1]*A[6] - A[0]*A[7]), a8 = (A[0]*A[4] - A[1]*A[3]);
248  *A++ = a0 / det; *A++ = a3 / det; *A++ = a6 / det;
249  *A++ = a1 / det; *A++ = a4 / det; *A++ = a7 / det;
250  *A++ = a2 / det; *A++ = a5 / det; *A++ = a8 / det;
251  return det;
252  }
253  default:
254  {
255  size_type NN = N*N;
256  if (__aux1().size() < NN) __aux1().resize(NN);
257  std::copy(A, A+NN, __aux1().begin());
258  __ipvt_aux().resize(N);
259  size_type info = lu_factor(&(*(__aux1().begin())), __ipvt_aux(), N);
260  GMM_ASSERT1(!doassert || !info, "Non invertible matrix, pivot = "
261  << info);
262  if (!info) lu_inverse(&(*(__aux1().begin())), __ipvt_aux(), A, N);
263  return lu_det(&(*(__aux1().begin())), __ipvt_aux(), N);
264  }
265  }
266  }
267 
268 
269 
271  (const base_matrix &G, const base_matrix &pc, base_matrix &K) const {
272  // gmm::mult(G, pc, K);
273  // Faster than the lapack call on my config ...
274  size_type N=gmm::mat_nrows(G), P=gmm::mat_nrows(pc), Q=gmm::mat_ncols(pc);
275  if (N && P && Q) {
276  auto itK = K.begin();
277  for (size_type j = 0; j < Q; ++j) {
278  auto itpc_j = pc.begin() + j*P, itG_b = G.begin();
279  for (size_type i = 0; i < N; ++i, ++itG_b) {
280  auto itG = itG_b, itpc = itpc_j;
281  scalar_type a = *(itG) * (*itpc);
282  for (size_type k = 1; k < P; ++k)
283  { itG += N; a += *(itG) * (*++itpc); }
284  *itK++ = a;
285  }
286  }
287  } else gmm::clear(K);
288  }
289 
291  if (!have_xref()) {
292  if (pspt_) xref_ = (*pspt_)[ii_];
293  else GMM_ASSERT1(false, "Missing xref");
294  }
295  return xref_;
296  }
297 
299  if (!have_xreal()) {
300  if (have_pgp()) {
301  xreal_ = pgp_->transform(ii_, G());
302  } else xreal_ = pgt()->transform(xref(),G());
303  }
304  return xreal_;
305  }
306 
308  GMM_ASSERT1(have_G(),
309  "Convex center can be provided only if matrix G is available");
310  if (!have_cv_center_) {
311  cv_center_.resize(G().nrows());
312  size_type nb_pts = G().ncols();
313  for (size_type i=0; i < nb_pts; i++)
314  gmm::add(gmm::mat_col(G(),i), cv_center_);
315  gmm::scale(cv_center_, scalar_type(1)/scalar_type(nb_pts));
316  have_cv_center_ = true;
317  }
318  return cv_center_;
319  }
320 
321  void geotrans_interpolation_context::compute_J() const {
322  GMM_ASSERT1(have_G() && have_pgt(), "Unable to compute J\n");
323  size_type P = pgt_->structure()->dim();
324  const base_matrix &KK = K();
325  if (P != N()) {
326  B_factors.base_resize(P, P);
327  gmm::mult(gmm::transposed(KK), KK, B_factors);
328  // gmm::abs below because on flat convexes determinant could be -1e-27.
329  J__ = J_ =::sqrt(gmm::abs(bgeot::lu_inverse(&(*(B_factors.begin())), P)));
330  } else {
331  auto it = &(*(KK.begin()));
332  switch (P) {
333  case 1: J__ = *it; break;
334  case 2: J__ = (*it) * (it[3]) - (it[1]) * (it[2]); break;
335  case 3:
336  {
337  B_.base_resize(P, P); // co-factors
338  auto itB = B_.begin();
339  scalar_type a0 = itB[0] = it[4]*it[8] - it[5]*it[7];
340  scalar_type a1 = itB[1] = it[5]*it[6] - it[3]*it[8];
341  scalar_type a2 = itB[2] = it[3]*it[7] - it[4]*it[6];
342  J__ = it[0] * a0 + it[1] * a1 + it[2] * a2;
343  } break;
344  default:
345  B_factors.base_resize(P, P); // store factorization for B computation
346  gmm::copy(gmm::transposed(KK), B_factors);
347  ipvt.resize(P);
348  bgeot::lu_factor(&(*(B_factors.begin())), ipvt, P);
349  J__ = bgeot::lu_det(&(*(B_factors.begin())), ipvt, P);
350  break;
351  }
352  J_ = gmm::abs(J__);
353  }
354  have_J_ = true;
355  }
356 
357  const base_matrix& geotrans_interpolation_context::K() const {
358  if (!have_K()) {
359  GMM_ASSERT1(have_G() && have_pgt(), "Unable to compute K\n");
360  size_type P = pgt_->structure()->dim();
361  K_.base_resize(N(), P);
362  if (have_pgp()) {
363  pgt_->compute_K_matrix(*G_, pgp_->grad(ii_), K_);
364  } else {
365  PC.base_resize(pgt_->nb_points(), P);
366  pgt_->poly_vector_grad(xref(), PC);
367  pgt_->compute_K_matrix(*G_, PC, K_);
368  }
369  have_K_ = true;
370  }
371  return K_;
372  }
373 
374  const base_matrix& geotrans_interpolation_context::B() const {
375  if (!have_B()) {
376  const base_matrix &KK = K();
377  size_type P = pgt_->structure()->dim(), N_ = gmm::mat_nrows(KK);
378  B_.base_resize(N_, P);
379  if (!have_J_) compute_J();
380  GMM_ASSERT1(J__ != scalar_type(0), "Non invertible matrix");
381  if (P != N_) {
382  gmm::mult(KK, B_factors, B_);
383  } else {
384  switch(P) {
385  case 1: B_(0, 0) = scalar_type(1) / J__; break;
386  case 2:
387  {
388  auto it = &(*(KK.begin())); auto itB = &(*(B_.begin()));
389  *itB++ = it[3] / J__;
390  *itB++ = -it[2] / J__;
391  *itB++ = -it[1] / J__;
392  *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  if (grad_computed_) return;
509  GLOBAL_OMP_GUARD
510  if (grad_computed_) return;
511  size_type R = trans.size();
512  dim_type n = dim();
513  grad_.resize(R);
514  for (size_type i = 0; i < R; ++i) {
515  grad_[i].resize(n);
516  for (dim_type j = 0; j < n; ++j) {
517  grad_[i][j] = trans[i]; grad_[i][j].derivative(j);
518  }
519  }
520  grad_computed_ = true;
521  }
522 
523  void compute_hess_() const {
524  if (hess_computed_) return;
525  GLOBAL_OMP_GUARD
526  if (hess_computed_) return;
527  size_type R = trans.size();
528  dim_type n = dim();
529  hess_.resize(R);
530  for (size_type i = 0; i < R; ++i) {
531  hess_[i].resize(n*n);
532  for (dim_type j = 0; j < n; ++j) {
533  for (dim_type k = 0; k < n; ++k) {
534  hess_[i][j+k*n] = trans[i];
535  hess_[i][j+k*n].derivative(j); hess_[i][j+k*n].derivative(k);
536  }
537  }
538  }
539  hess_computed_ = true;
540  }
541 
542  virtual void poly_vector_val(const base_node &pt, base_vector &val) const {
543  val.resize(nb_points());
544  for (size_type k = 0; k < nb_points(); ++k)
545  val[k] = to_scalar(trans[k].eval(pt.begin()));
546  }
547 
548  virtual void poly_vector_val(const base_node &pt,
549  const convex_ind_ct &ind_ct,
550  base_vector &val) const {
551  size_type nb_funcs=ind_ct.size();
552  val.resize(nb_funcs);
553  for (size_type k = 0; k < nb_funcs; ++k)
554  val[k] = to_scalar(trans[ind_ct[k]].eval(pt.begin()));
555  }
556 
557  virtual void poly_vector_grad(const base_node &pt, base_matrix &pc) const {
558  if (!grad_computed_) compute_grad_();
559  FUNC PP;
560  pc.base_resize(nb_points(),dim());
561  for (size_type i = 0; i < nb_points(); ++i)
562  for (dim_type n = 0; n < dim(); ++n)
563  pc(i, n) = to_scalar(grad_[i][n].eval(pt.begin()));
564  }
565 
566  virtual void poly_vector_grad(const base_node &pt,
567  const convex_ind_ct &ind_ct,
568  base_matrix &pc) const {
569  if (!grad_computed_) compute_grad_();
570  FUNC PP;
571  size_type nb_funcs=ind_ct.size();
572  pc.base_resize(nb_funcs,dim());
573  for (size_type i = 0; i < nb_funcs; ++i)
574  for (dim_type n = 0; n < dim(); ++n)
575  pc(i, n) = to_scalar(grad_[ind_ct[i]][n].eval(pt.begin()));
576  }
577 
578  virtual void poly_vector_hess(const base_node &pt, base_matrix &pc) const {
579  if (!hess_computed_) compute_hess_();
580  FUNC PP, QP;
581  pc.base_resize(nb_points(),dim()*dim());
582  for (size_type i = 0; i < nb_points(); ++i)
583  for (dim_type n = 0; n < dim(); ++n) {
584  for (dim_type m = 0; m <= n; ++m)
585  pc(i, n*dim()+m) = pc(i, m*dim()+n) =
586  to_scalar(hess_[i][m*dim()+n].eval(pt.begin()));
587  }
588  }
589 
590  };
591 
592  typedef igeometric_trans<base_poly> poly_geometric_trans;
593  typedef igeometric_trans<polynomial_composite> comppoly_geometric_trans;
594  typedef igeometric_trans<base_rational_fraction> fraction_geometric_trans;
595 
596  /* ******************************************************************** */
597  /* transformation on simplex. */
598  /* ******************************************************************** */
599 
600  struct simplex_trans_ : public poly_geometric_trans {
601  void calc_base_func(base_poly &p, size_type i, short_type K) const {
602  dim_type N = dim();
603  base_poly l0(N, 0), l1(N, 0);
604  power_index w(short_type(N+1));
605  l0.one(); l1.one(); p = l0;
606  for (short_type nn = 0; nn < N; ++nn) l0 -= base_poly(N, 1, nn);
607 
608  w[0] = K;
609  for (int nn = 1; nn <= N; ++nn) {
610  w[nn]=short_type(floor(0.5+(((cvr->points())[i])[nn-1]*double(K))));
611  w[0]=short_type(w[0]-w[nn]);
612  }
613 
614  for (short_type nn = 0; nn <= N; ++nn)
615  for (short_type j = 0; j < w[nn]; ++j)
616  if (nn == 0)
617  p *= (l0 * (scalar_type(K) / scalar_type(j+1)))
618  - (l1 * (scalar_type(j) / scalar_type(j+1)));
619  else
620  p *= (base_poly(N, 1, short_type(nn-1)) * (scalar_type(K) / scalar_type(j+1)))
621  - (l1 * (scalar_type(j) / scalar_type(j+1)));
622  }
623 
624  simplex_trans_(dim_type nc, short_type k) {
625  cvr = simplex_of_reference(nc, k);
626  size_type R = cvr->structure()->nb_points();
627  is_lin = (k == 1);
628  complexity_ = k;
629  trans.resize(R);
630  for (size_type r = 0; r < R; ++r) calc_base_func(trans[r], r, k);
631  fill_standard_vertices();
632  }
633  };
634 
635  static pgeometric_trans
636  PK_gt(gt_param_list &params,
637  std::vector<dal::pstatic_stored_object> &dependencies) {
638  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
639  << params.size() << " should be 2.");
640  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
641  "Bad type of parameters");
642  int n = int(::floor(params[0].num() + 0.01));
643  int k = int(::floor(params[1].num() + 0.01));
644  GMM_ASSERT1(n >= 0 && n < 100 && k >= 0 && k <= 150 &&
645  double(n) == params[0].num() && double(k) == params[1].num(),
646  "Bad parameters");
647  dependencies.push_back(simplex_of_reference(dim_type(n), dim_type(k)));
648  return std::make_shared<simplex_trans_>(dim_type(n), dim_type(k));
649  }
650 
651  /* ******************************************************************** */
652  /* direct product transformation */
653  /* ******************************************************************** */
654 
655  struct cv_pr_t_ : public poly_geometric_trans {
656  cv_pr_t_(const poly_geometric_trans *a, const poly_geometric_trans *b) {
657  cvr = convex_ref_product(a->convex_ref(), b->convex_ref());
658  is_lin = false;
659  complexity_ = a->complexity() * b->complexity();
660 
661  size_type n1 = a->nb_points(), n2 = b->nb_points();
662  trans.resize(n1 * n2);
663  for (size_type i1 = 0; i1 < n1; ++i1)
664  for (size_type i2 = 0; i2 < n2; ++i2) {
665  trans[i1 + i2 * n1] = a->trans[i1];
666  trans[i1 + i2 * n1].direct_product(b->trans[i2]);
667  }
668  for (size_type i2 = 0; i2 < b->nb_vertices(); ++i2)
669  for (size_type i1 = 0; i1 < a->nb_vertices(); ++i1)
670  vertices_.push_back(a->vertices()[i1] + b->vertices()[i2] * n1);
671  }
672  };
673 
674  static pgeometric_trans product_gt(gt_param_list &params,
675  std::vector<dal::pstatic_stored_object> &dependencies) {
676  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
677  << params.size() << " should be 2.");
678  GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
679  "Bad type of parameters");
680  pgeometric_trans a = params[0].method();
681  pgeometric_trans b = params[1].method();
682  dependencies.push_back(a); dependencies.push_back(b);
683  dependencies.push_back(convex_ref_product(a->convex_ref(),
684  b->convex_ref()));
685  const poly_geometric_trans *aa
686  = dynamic_cast<const poly_geometric_trans *>(a.get());
687  const poly_geometric_trans *bb
688  = dynamic_cast<const poly_geometric_trans *>(b.get());
689  GMM_ASSERT1(aa && bb, "The product of geometric transformations "
690  "is only defined for polynomial ones");
691  return std::make_shared<cv_pr_t_>(aa, bb);
692  }
693 
694  /* ******************************************************************** */
695  /* linear direct product transformation. */
696  /* ******************************************************************** */
697 
698  struct cv_pr_tl_ : public poly_geometric_trans {
699  cv_pr_tl_(const poly_geometric_trans *a, const poly_geometric_trans *b) {
700  GMM_ASSERT1(a->is_linear() && b->is_linear(),
701  "linear product of non-linear transformations");
702  cvr = convex_ref_product(a->convex_ref(), b->convex_ref());
703  is_lin = true;
704  complexity_ = std::max(a->complexity(), b->complexity());
705 
706  trans.resize(a->nb_points() * b->nb_points());
707  std::fill(trans.begin(), trans.end(), null_poly(dim()));
708 
709  std::stringstream name;
710  name << "GT_PK(" << int(dim()) << ",1)";
711  pgeometric_trans pgt_ = geometric_trans_descriptor(name.str());
712  const poly_geometric_trans *pgt
713  = dynamic_cast<const poly_geometric_trans *>(pgt_.get());
714 
715  for (size_type i = 0; i <= dim(); ++i)
716  trans[cvr->structure()->ind_dir_points()[i]]
717  = pgt->trans[i];
718  for (size_type i2 = 0; i2 < b->nb_vertices(); ++i2)
719  for (size_type i1 = 0; i1 < a->nb_vertices(); ++i1)
720  vertices_.push_back(a->vertices()[i1]
721  + b->vertices()[i2] * a->nb_points());
722  }
723  };
724 
725  static pgeometric_trans linear_product_gt(gt_param_list &params,
726  std::vector<dal::pstatic_stored_object> &dependencies) {
727  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
728  << params.size() << " should be 2.");
729  GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
730  "Bad type of parameters");
731  pgeometric_trans a = params[0].method();
732  pgeometric_trans b = params[1].method();
733  dependencies.push_back(a); dependencies.push_back(b);
734  dependencies.push_back(convex_ref_product(a->convex_ref(),
735  b->convex_ref()));
736  const poly_geometric_trans *aa
737  = dynamic_cast<const poly_geometric_trans *>(a.get());
738  const poly_geometric_trans *bb
739  = dynamic_cast<const poly_geometric_trans *>(b.get());
740  GMM_ASSERT1(aa && bb, "The product of geometric transformations "
741  "is only defined for polynomial ones");
742  return std::make_shared<cv_pr_tl_>(aa, bb);
743  }
744 
745  /* ******************************************************************** */
746  /* parallelepiped transformation. */
747  /* ******************************************************************** */
748 
749  static pgeometric_trans QK_gt(gt_param_list &params,
750  std::vector<dal::pstatic_stored_object> &) {
751  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
752  << params.size() << " should be 2.");
753  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
754  "Bad type of parameters");
755  int n = int(::floor(params[0].num() + 0.01));
756  int k = int(::floor(params[1].num() + 0.01));
757  GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
758  double(n) == params[0].num() && double(k) == params[1].num(),
759  "Bad parameters");
760  std::stringstream name;
761  if (n == 1)
762  name << "GT_PK(1," << k << ")";
763  else
764  name << "GT_PRODUCT(GT_QK(" << n-1 << "," << k << "),GT_PK(1,"
765  << k << "))";
766  return geometric_trans_descriptor(name.str());
767  }
768 
769  static pgeometric_trans
770  prism_pk_gt(gt_param_list &params,
771  std::vector<dal::pstatic_stored_object> &) {
772  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
773  << params.size() << " should be 2.");
774  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
775  "Bad type of parameters");
776  int n = int(::floor(params[0].num() + 0.01));
777  int k = int(::floor(params[1].num() + 0.01));
778  GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
779  double(n) == params[0].num() && double(k) == params[1].num(),
780  "Bad parameters");
781  std::stringstream name;
782  name << "GT_PRODUCT(GT_PK(" << n-1 << "," << k << "),GT_PK(1,"
783  << k << "))";
784  return geometric_trans_descriptor(name.str());
785  }
786 
787  static pgeometric_trans
788  linear_qk(gt_param_list &params,
789  std::vector<dal::pstatic_stored_object> &) {
790  GMM_ASSERT1(params.size() == 1, "Bad number of parameters : "
791  << params.size() << " should be 1.");
792  GMM_ASSERT1(params[0].type() == 0, "Bad type of parameters");
793  int n = int(::floor(params[0].num() + 0.01));
794  return parallelepiped_linear_geotrans(n);
795  }
796 
797 
798  /* ******************************************************************** */
799  /* Incomplete Q2 geometric transformation for n=2 or 3. */
800  /* ******************************************************************** */
801  /* By Yao Koutsawa <yao.koutsawa@tudor.lu> 2012-12-10 */
802 
803  struct Q2_incomplete_trans_: public poly_geometric_trans {
804  Q2_incomplete_trans_(dim_type nc) {
805  cvr = Q2_incomplete_of_reference(nc);
806  size_type R = cvr->structure()->nb_points();
807  is_lin = false;
808  complexity_ = 2;
809  trans.resize(R);
810 
811  if (nc == 2) {
812  std::stringstream s
813  ( "1 - 2*x^2*y - 2*x*y^2 + 2*x^2 + 5*x*y + 2*y^2 - 3*x - 3*y;"
814  "4*(x^2*y - x^2 - x*y + x);"
815  "2*x*y*y - 2*x*x*y + 2*x*x - x*y - x;"
816  "4*(x*y*y - x*y - y*y + y);"
817  "4*(x*y - x*y*y);"
818  "2*x*x*y - 2*x*y*y - x*y + 2*y*y - y;"
819  "4*(x*y - x*x*y);"
820  "2*x*x*y + 2*x*y*y - 3*x*y;");
821 
822  for (int i = 0; i < 8; ++i)
823  trans[i] = read_base_poly(2, s);
824  } else {
825  std::stringstream s
826  ("1 + 2*x^2*y*z + 2*x*y^2*z + 2*x*y*z^2"
827  " - 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"
828  " + 2*x^2 + 2*y^2 + 2*z^2 + 5*y*z + 5*x*z + 5*x*y - 3*x - 3*y - 3*z;"
829  "4*( - x^2*y*z + x*y*z + x^2*z - x*z + x^2*y - x*y - x^2 + x);"
830  "2*x^2*y*z - 2*x*y^2*z - 2*x*y*z^2"
831  " - 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;"
832  "4*( - x*y^2*z + x*y^2 + y^2*z + x*y*z - x*y - y^2 - y*z + y);"
833  "4*(x*y^2*z - x*y^2 - x*y*z + x*y);"
834  " - 2*x^2*y*z + 2*x*y^2*z - 2*x*y*z^2"
835  " + 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;"
836  "4*(x^2*y*z - x^2*y - x*y*z + x*y);"
837  " - 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;"
838  "4*( - x*y*z^2 + x*z^2 + y*z^2 + x*y*z - x*z - y*z - z^2 + z);"
839  "4*(x*y*z^2 - x*y*z - x*z^2 + x*z);"
840  "4*(x*y*z^2 - x*y*z - y*z^2 + y*z);"
841  "4*( - x*y*z^2 + x*y*z);"
842  " - 2*x^2*y*z - 2*x*y^2*z + 2*x*y*z^2"
843  " + 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;"
844  "4*(x^2*y*z - x^2*z - x*y*z + x*z);"
845  " - 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;"
846  "4*(x*y^2*z - y^2*z - x*y*z + y*z);"
847  "4*( - x*y^2*z + x*y*z);"
848  "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;"
849  "4*( - x^2*y*z + x*y*z);"
850  "2*x^2*y*z + 2*x*y^2*z + 2*x*y*z^2 - 5*x*y*z;");
851 
852  for (int i = 0; i < 20; ++i)
853  trans[i] = read_base_poly(3, s);
854  }
855  fill_standard_vertices();
856  }
857  };
858 
859  static pgeometric_trans
860  Q2_incomplete_gt(gt_param_list& params,
861  std::vector<dal::pstatic_stored_object> &dependencies) {
862  GMM_ASSERT1(params.size() == 1, "Bad number of parameters : "
863  << params.size() << " should be 1.");
864  GMM_ASSERT1(params[0].type() == 0, "Bad type of parameters");
865  int n = int(::floor(params[0].num() + 0.01));
866  GMM_ASSERT1(n == 2 || n == 3, "Bad parameter, expected value 2 or 3");
867 
868  dependencies.push_back(Q2_incomplete_of_reference(dim_type(n)));
869  return std::make_shared<Q2_incomplete_trans_>(dim_type(n));
870  }
871 
872  pgeometric_trans Q2_incomplete_geotrans(dim_type nc) {
873  std::stringstream name;
874  name << "GT_Q2_INCOMPLETE(" << nc << ")";
875  return geometric_trans_descriptor(name.str());
876  }
877 
878  /* ******************************************************************** */
879  /* Pyramidal geometric transformation of order k=1 or 2. */
880  /* ******************************************************************** */
881 
882  struct pyramid_QK_trans_: public fraction_geometric_trans {
883  pyramid_QK_trans_(short_type k) {
884  cvr = pyramid_QK_of_reference(k);
885  size_type R = cvr->structure()->nb_points();
886  is_lin = false;
887  complexity_ = k;
888  trans.resize(R);
889 
890  if (k == 1) {
891  base_rational_fraction Q(read_base_poly(3, "x*y"), // Q = xy/(1-z)
892  read_base_poly(3, "1-z"));
893  trans[0] = (read_base_poly(3, "1-x-y-z") + Q)*0.25;
894  trans[1] = (read_base_poly(3, "1+x-y-z") - Q)*0.25;
895  trans[2] = (read_base_poly(3, "1-x+y-z") - Q)*0.25;
896  trans[3] = (read_base_poly(3, "1+x+y-z") + Q)*0.25;
897  trans[4] = read_base_poly(3, "z");
898  } else if (k == 2) {
899  base_poly xi0 = read_base_poly(3, "(1-z-x)*0.5");
900  base_poly xi1 = read_base_poly(3, "(1-z-y)*0.5");
901  base_poly xi2 = read_base_poly(3, "(1-z+x)*0.5");
902  base_poly xi3 = read_base_poly(3, "(1-z+y)*0.5");
903  base_poly x = read_base_poly(3, "x");
904  base_poly y = read_base_poly(3, "y");
905  base_poly z = read_base_poly(3, "z");
906  base_poly ones = read_base_poly(3, "1");
907  base_poly un_z = read_base_poly(3, "1-z");
908  base_rational_fraction Q(read_base_poly(3, "1"), un_z); // Q = 1/(1-z)
909  trans[ 0] = Q*Q*xi0*xi1*(x*y-z*un_z);
910  trans[ 1] = Q*Q*xi0*xi1*xi2*(xi1*2.-un_z)*4.;
911  trans[ 2] = Q*Q*xi1*xi2*(-x*y-z*un_z);
912  trans[ 3] = Q*Q*xi3*xi0*xi1*(xi0*2.-un_z)*4.;
913  trans[ 4] = Q*Q*xi0*xi1*xi2*xi3*16.;
914  trans[ 5] = Q*Q*xi1*xi2*xi3*(xi2*2.-un_z)*4.;
915  trans[ 6] = Q*Q*xi3*xi0*(-x*y-z*un_z);
916  trans[ 7] = Q*Q*xi2*xi3*xi0*(xi3*2.-un_z)*4.;
917  trans[ 8] = Q*Q*xi2*xi3*(x*y-z*un_z);
918  trans[ 9] = Q*z*xi0*xi1*4.;
919  trans[10] = Q*z*xi1*xi2*4.;
920  trans[11] = Q*z*xi3*xi0*4.;
921  trans[12] = Q*z*xi2*xi3*4.;
922  trans[13] = read_base_poly(3, "z*(2*z-1)");
923  }
924  fill_standard_vertices();
925  }
926  };
927 
928  static pgeometric_trans
929  pyramid_QK_gt(gt_param_list& params,
930  std::vector<dal::pstatic_stored_object> &deps) {
931  GMM_ASSERT1(params.size() == 1, "Bad number of parameters : "
932  << params.size() << " should be 1.");
933  GMM_ASSERT1(params[0].type() == 0, "Bad type of parameters");
934  int k = int(::floor(params[0].num() + 0.01));
935 
936  deps.push_back(pyramid_QK_of_reference(dim_type(k)));
937  return std::make_shared<pyramid_QK_trans_>(dim_type(k));
938  }
939 
940  pgeometric_trans pyramid_QK_geotrans(short_type k) {
941  static short_type k_ = -1;
942  static pgeometric_trans pgt = 0;
943  if (k != k_) {
944  std::stringstream name;
945  name << "GT_PYRAMID(" << k << ")";
946  pgt = geometric_trans_descriptor(name.str());
947  }
948  return pgt;
949  }
950 
951  /* ******************************************************************** */
952  /* Incomplete quadratic pyramidal geometric transformation. */
953  /* ******************************************************************** */
954 
955  struct pyramid_Q2_incomplete_trans_: public fraction_geometric_trans {
956  pyramid_Q2_incomplete_trans_() {
958  size_type R = cvr->structure()->nb_points();
959  is_lin = false;
960  complexity_ = 2;
961  trans.resize(R);
962 
963  base_poly xy = read_base_poly(3, "x*y");
964  base_poly z = read_base_poly(3, "z");
965 
966  base_poly p00m = read_base_poly(3, "1-z");
967 
968  base_poly pmmm = read_base_poly(3, "1-x-y-z");
969  base_poly ppmm = read_base_poly(3, "1+x-y-z");
970  base_poly pmpm = read_base_poly(3, "1-x+y-z");
971  base_poly pppm = read_base_poly(3, "1+x+y-z");
972 
973  base_poly mmm0_ = read_base_poly(3, "-1-x-y")*0.25;
974  base_poly mpm0_ = read_base_poly(3, "-1+x-y")*0.25;
975  base_poly mmp0_ = read_base_poly(3, "-1-x+y")*0.25;
976  base_poly mpp0_ = read_base_poly(3, "-1+x+y")*0.25;
977 
978  base_poly pp0m = read_base_poly(3, "1+x-z");
979  base_poly pm0m = read_base_poly(3, "1-x-z");
980  base_poly p0mm = read_base_poly(3, "1-y-z");
981  base_poly p0pm = read_base_poly(3, "1+y-z");
982 
983  trans[ 0] = mmm0_ * pmmm + base_rational_fraction(mmm0_ * xy, p00m); // N5 (Bedrosian, 1992)
984  trans[ 1] = base_rational_fraction(pp0m * pm0m * p0mm * 0.5, p00m); // N6
985  trans[ 2] = mpm0_ * ppmm - base_rational_fraction(mpm0_ * xy, p00m); // N7
986  trans[ 3] = base_rational_fraction(p0pm * p0mm * pm0m * 0.5, p00m); // N4
987  trans[ 4] = base_rational_fraction(p0pm * p0mm * pp0m * 0.5, p00m); // N8
988  trans[ 5] = mmp0_ * pmpm - base_rational_fraction(mmp0_ * xy, p00m); // N3
989  trans[ 6] = base_rational_fraction(pp0m * pm0m * p0pm * 0.5, p00m); // N2
990  trans[ 7] = mpp0_ * pppm + base_rational_fraction(mpp0_ * xy, p00m); // N1
991  trans[ 8] = base_rational_fraction(pm0m * p0mm * z, p00m); // N11
992  trans[ 9] = base_rational_fraction(pp0m * p0mm * z, p00m); // N12
993  trans[10] = base_rational_fraction(pm0m * p0pm * z, p00m); // N10
994  trans[11] = base_rational_fraction(pp0m * p0pm * z, p00m); // N9
995  trans[12] = read_base_poly(3, "2*z^2-z"); // N13
996 
997  fill_standard_vertices();
998  }
999  };
1000 
1001  static pgeometric_trans
1002  pyramid_Q2_incomplete_gt(gt_param_list& params,
1003  std::vector<dal::pstatic_stored_object> &deps) {
1004  GMM_ASSERT1(params.size() == 0, "Bad number of parameters : "
1005  << params.size() << " should be 0.");
1006 
1007  deps.push_back(pyramid_Q2_incomplete_of_reference());
1008  return std::make_shared<pyramid_Q2_incomplete_trans_>();
1009  }
1010 
1011  pgeometric_trans pyramid_Q2_incomplete_geotrans() {
1012  static pgeometric_trans pgt = 0;
1013  if (!pgt)
1014  pgt = geometric_trans_descriptor("GT_PYRAMID_Q2_INCOMPLETE");
1015  return pgt;
1016  }
1017 
1018  /* ******************************************************************** */
1019  /* Incomplete quadratic prism geometric transformation. */
1020  /* ******************************************************************** */
1021 
1022  struct prism_incomplete_P2_trans_: public poly_geometric_trans {
1023  prism_incomplete_P2_trans_() {
1025  size_type R = cvr->structure()->nb_points();
1026  is_lin = false;
1027  complexity_ = 2;
1028  trans.resize(R);
1029 
1030  std::stringstream s
1031  ( "-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"
1032  "-3*z+2*y^2+4*x*y-3*y+2*x^2-3*x+1;"
1033  "4*(x*y*z+x^2*z-x*z-x*y-x^2+x);"
1034  "2*x*z^2-2*x^2*z-x*z+2*x^2-x;"
1035  "4*(y^2*z+x*y*z-y*z-y^2-x*y+y);"
1036  "4*(x*y-x*y*z);"
1037  "2*y*z^2-2*y^2*z-y*z+2*y^2-y;"
1038  "4*(y*z^2+x*z^2-z^2-y*z-x*z+z);"
1039  "4*(x*z-x*z^2);"
1040  "4*(y*z-y*z^2);"
1041  "-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;"
1042  "4*(-x*y*z-x^2*z+x*z);"
1043  "2*x*z^2+2*x^2*z-3*x*z;"
1044  "4*(-y^2*z-x*y*z+y*z);"
1045  "4*x*y*z;"
1046  "2*y*z^2+2*y^2*z-3*y*z;");
1047 
1048  for (int i = 0; i < 15; ++i)
1049  trans[i] = read_base_poly(3, s);
1050 
1051  fill_standard_vertices();
1052  }
1053  };
1054 
1055  static pgeometric_trans
1056  prism_incomplete_P2_gt(gt_param_list& params,
1057  std::vector<dal::pstatic_stored_object> &deps) {
1058  GMM_ASSERT1(params.size() == 0, "Bad number of parameters : "
1059  << params.size() << " should be 0.");
1060 
1061  deps.push_back(prism_incomplete_P2_of_reference());
1062  return std::make_shared<prism_incomplete_P2_trans_>();
1063  }
1064 
1065  pgeometric_trans prism_incomplete_P2_geotrans() {
1066  static pgeometric_trans pgt = 0;
1067  if (!pgt)
1068  pgt = geometric_trans_descriptor("GT_PRISM_INCOMPLETE_P2");
1069  return pgt;
1070  }
1071 
1072  /* ******************************************************************** */
1073  /* Misc function. */
1074  /* ******************************************************************** */
1075 
1076  /* norm of returned vector is the ratio between the face surface on
1077  the reference element and the face surface on the real element.
1078  IT IS NOT UNITARY
1079  */
1080  base_small_vector
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() :
1140  dal::naming_system<geometric_trans>("GT") {
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  auto ptrans = name_system.method(name, i);
1166  auto &trans = const_cast<bgeot::geometric_trans&>(*ptrans);
1167  auto short_name = name_system.shorter_name_of_method(ptrans);
1168  trans.set_name(short_name);
1169  return ptrans;
1170  }
1171 
1174  const torus_geom_trans *pgt_torus = dynamic_cast<const torus_geom_trans *>(p.get());
1175  if (pgt_torus) return instance.shorter_name_of_method(pgt_torus->get_original_transformation());
1176  return instance.shorter_name_of_method(p);
1177  }
1178 
1179  /* Fonctions pour la ref. directe. */
1180 
1181  pgeometric_trans simplex_geotrans(size_type n, short_type k) {
1182  static pgeometric_trans pgt = 0;
1183  static size_type d = size_type(-2);
1184  static short_type r = short_type(-2);
1185  if (d != n || r != k) {
1186  std::stringstream name;
1187  name << "GT_PK(" << n << "," << k << ")";
1188  pgt = geometric_trans_descriptor(name.str());
1189  d = n; r = k;
1190  }
1191  return pgt;
1192  }
1193 
1194  pgeometric_trans parallelepiped_geotrans(size_type n, short_type k) {
1195  static pgeometric_trans pgt = 0;
1196  static size_type d = size_type(-2);
1197  static short_type r = short_type(-2);
1198  if (d != n || r != k) {
1199  std::stringstream name;
1200  name << "GT_QK(" << n << "," << k << ")";
1201  pgt = geometric_trans_descriptor(name.str());
1202  d = n; r = k;
1203  }
1204  return pgt;
1205  }
1206 
1207  static std::string name_of_linear_qk_trans(size_type dim) {
1208  switch (dim) {
1209  case 1: return "GT_PK(1,1)";
1210  default: return std::string("GT_LINEAR_PRODUCT(")
1211  + name_of_linear_qk_trans(dim-1)
1212  + std::string(",GT_PK(1,1))");
1213  }
1214  }
1215 
1216  pgeometric_trans parallelepiped_linear_geotrans(size_type n) {
1217  static pgeometric_trans pgt = 0;
1218  static size_type d = size_type(-2);
1219  if (d != n) {
1220  std::stringstream name(name_of_linear_qk_trans(n));
1221  pgt = geometric_trans_descriptor(name.str());
1222  d = n;
1223  }
1224  return pgt;
1225  }
1226 
1227  pgeometric_trans prism_linear_geotrans(size_type n) {
1228  static pgeometric_trans pgt = 0;
1229  static size_type d = size_type(-2);
1230  if (d != n) {
1231  std::stringstream name;
1232  name << "GT_LINEAR_PRODUCT(GT_PK(" << (n-1) << ", 1), GT_PK(1,1))";
1233  pgt = geometric_trans_descriptor(name.str());
1234  d = n;
1235  }
1236  return pgt;
1237  }
1238 
1239  pgeometric_trans linear_product_geotrans(pgeometric_trans pg1,
1240  pgeometric_trans pg2) {
1241  std::stringstream name;
1242  name << "GT_LINEAR_PRODUCT(" << name_of_geometric_trans(pg1) << ","
1243  << name_of_geometric_trans(pg2) << ")";
1244  return geometric_trans_descriptor(name.str());
1245  }
1246 
1247  pgeometric_trans prism_geotrans(size_type n, short_type k) {
1248  static pgeometric_trans pgt = 0;
1249  static size_type d = size_type(-2);
1250  static short_type r = short_type(-2);
1251  if (d != n || r != k) {
1252  std::stringstream name;
1253  name << "GT_PRISM(" << n << "," << k << ")";
1254  pgt = geometric_trans_descriptor(name.str());
1255  d = n; r = k;
1256  }
1257  return pgt;
1258  }
1259 
1260  pgeometric_trans product_geotrans(pgeometric_trans pg1,
1261  pgeometric_trans pg2) {
1262  static pgeometric_trans pgt = 0;
1263  static pgeometric_trans pg1_ = 0;
1264  static pgeometric_trans pg2_ = 0;
1265  if (pg1 != pg1_ || pg2 != pg2_) {
1266  std::stringstream name;
1267  name << "GT_PRODUCT(" << name_of_geometric_trans(pg1) << ","
1268  << name_of_geometric_trans(pg2) << ")";
1269  pgt = geometric_trans_descriptor(name.str());
1270  pg1_ = pg1; pg2_ = pg2;
1271  }
1272  return pgt;
1273  }
1274 
1275 
1276  // To be completed
1277  pgeometric_trans default_trans_of_cvs(pconvex_structure cvs) {
1278 
1279  dim_type n = cvs->dim();
1280  short_type nbf = cvs->nb_faces();
1281  short_type nbpt = cvs->nb_points();
1282 
1283  // Basic cases
1284  if (cvs == simplex_structure(n)) return simplex_geotrans(n, 1);
1285  if (cvs == parallelepiped_structure(n))
1286  return parallelepiped_geotrans(n, 1);
1287  if (cvs == prism_P1_structure(n)) return prism_geotrans(n, 1);
1288 
1289  // more elaborated ones
1290  switch (n) {
1291  case 1 : return simplex_geotrans(1, short_type(nbpt-1));
1292  case 2 :
1293  if (nbf == 3) {
1294  short_type k = short_type(round((sqrt(1.+8.*nbpt) - 3. ) / 2.));
1295  if (cvs == simplex_structure(2,k)) return simplex_geotrans(2, k);
1296  } else if (nbf == 4) {
1297  short_type k = short_type(round(sqrt(1.*nbpt)) - 1.);
1298  if (cvs == parallelepiped_structure(2, k))
1299  return parallelepiped_geotrans(2, k);
1300  }
1301  break;
1302  case 3 :
1303  if (nbf == 4) {
1304  if (cvs == simplex_structure(3, 2)) return simplex_geotrans(3, 2);
1305  if (cvs == simplex_structure(3, 3)) return simplex_geotrans(3, 3);
1306  if (cvs == simplex_structure(3, 4)) return simplex_geotrans(3, 4);
1307  if (cvs == simplex_structure(3, 5)) return simplex_geotrans(3, 5);
1308  if (cvs == simplex_structure(3, 6)) return simplex_geotrans(3, 6);
1309  } else if (nbf == 6) {
1310  short_type k = short_type(round(pow(1.*nbpt, 1./3.)) - 1.);
1311  if (cvs == parallelepiped_structure(3, k))
1312  return parallelepiped_geotrans(3, k);
1313  } else if (nbf == 5) {
1314  if (cvs == pyramid_QK_structure(1)) return pyramid_QK_geotrans(1);
1315  if (cvs == pyramid_QK_structure(2)) return pyramid_QK_geotrans(2);
1316  if (cvs == pyramid_QK_structure(3)) return pyramid_QK_geotrans(3);
1317  if (cvs == pyramid_QK_structure(4)) return pyramid_QK_geotrans(4);
1318  if (cvs == pyramid_QK_structure(5)) return pyramid_QK_geotrans(5);
1319  if (cvs == pyramid_QK_structure(6)) return pyramid_QK_geotrans(6);
1320  if (cvs == pyramid_Q2_incomplete_structure())
1321  return pyramid_Q2_incomplete_geotrans();
1322  }
1323  break;
1324  }
1325  GMM_ASSERT1(false, "Unrecognized structure");
1326  }
1327 
1328 
1329 
1330  /* ********************************************************************* */
1331  /* Precomputation on geometric transformations. */
1332  /* ********************************************************************* */
1333 
1334  DAL_DOUBLE_KEY(pre_geot_key_, pgeometric_trans, pstored_point_tab);
1335 
1336  geotrans_precomp_::geotrans_precomp_(pgeometric_trans pg,
1337  pstored_point_tab ps)
1338  : pgt(pg), pspt(ps)
1339  { DAL_STORED_OBJECT_DEBUG_CREATED(this, "Geotrans precomp"); }
1340 
1341  void geotrans_precomp_::init_val() const {
1342  c.clear();
1343  c.resize(pspt->size(), base_vector(pgt->nb_points()));
1344  for (size_type j = 0; j < pspt->size(); ++j)
1345  pgt->poly_vector_val((*pspt)[j], c[j]);
1346  }
1347 
1348  void geotrans_precomp_::init_grad() const {
1349  dim_type N = pgt->dim();
1350  pc.clear();
1351  pc.resize(pspt->size(), base_matrix(pgt->nb_points() , N));
1352  for (size_type j = 0; j < pspt->size(); ++j)
1353  pgt->poly_vector_grad((*pspt)[j], pc[j]);
1354  }
1355 
1356  void geotrans_precomp_::init_hess() const {
1357  base_poly P, Q;
1358  dim_type N = pgt->structure()->dim();
1359  hpc.clear();
1360  hpc.resize(pspt->size(), base_matrix(pgt->nb_points(), gmm::sqr(N)));
1361  for (size_type j = 0; j < pspt->size(); ++j)
1362  pgt->poly_vector_hess((*pspt)[j], hpc[j]);
1363  }
1364 
1365  base_node geotrans_precomp_::transform(size_type i,
1366  const base_matrix &G) const {
1367  if (c.empty()) init_val();
1368  size_type N = G.nrows(), k = pgt->nb_points();
1369  base_node P(N);
1370  base_matrix::const_iterator git = G.begin();
1371  for (size_type l = 0; l < k; ++l) {
1372  scalar_type a = c[i][l];
1373  base_node::iterator pit = P.begin(), pite = P.end();
1374  for (; pit != pite; ++git, ++pit) *pit += a * (*git);
1375  }
1376  return P;
1377  }
1378 
1379  pgeotrans_precomp geotrans_precomp(pgeometric_trans pg,
1380  pstored_point_tab pspt,
1381  dal::pstatic_stored_object dep) {
1382  dal::pstatic_stored_object_key pk= std::make_shared<pre_geot_key_>(pg,pspt);
1383  dal::pstatic_stored_object o = dal::search_stored_object(pk);
1384  if (o) return std::dynamic_pointer_cast<const geotrans_precomp_>(o);
1385  pgeotrans_precomp p = std::make_shared<geotrans_precomp_>(pg, pspt);
1386  dal::add_stored_object(pk, p, pg, pspt, dal::AUTODELETE_STATIC_OBJECT);
1387  if (dep) dal::add_dependency(p, dep);
1388  return p;
1389  }
1390 
1391  void delete_geotrans_precomp(pgeotrans_precomp pgp)
1392  { dal::del_stored_object(pgp, true); }
1393 
1394 } /* end of namespace bgeot. */
1395 
Geometric transformations on convexes.
Handle composite polynomials.
Provides mesh of torus.
Description of a geometric transformation between a reference element and a real element.
dim_type dim() const
Dimension of the reference element.
size_type nb_points() const
Number of geometric nodes.
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.
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
virtual void poly_vector_val(const base_node &pt, base_vector &val) const =0
Gives the value of the functions vector at a certain point.
the geotrans_interpolation_context structure is passed as the argument of geometric transformation in...
const base_matrix & K() const
See getfem kernel doc for these matrices.
const base_matrix & G() const
matrix whose columns are the vertices of the convex
size_type ii_
if pgp != 0, it is the same as pgp's one
const base_node & xreal() const
coordinates of the current point, in the real convex.
const base_matrix * G_
transformed point
pgeometric_trans pgt_
see documentation (getfem kernel doc) for more details
base_node cv_center_
pointer to the matrix of real nodes of the convex
void set_xref(const base_node &P)
change the current point (coordinates given in the reference convex)
const base_node & xref() const
coordinates of the current point, in the reference convex.
const base_node & cv_center() const
coordinates of the center of the real convex.
base_matrix K_
real center of convex (average of columns of G)
scalar_type J_
index of current point in the pgp
Associate a name to a method descriptor and store method descriptors.
static T & instance()
Instance from the current thread.
A simple singleton implementation.
a balanced tree stored in a dal::dynamic_array
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:58
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1663
Basic Geometric Tools.
pconvex_ref convex_ref_product(pconvex_ref a, pconvex_ref b)
tensorial product of two convex ref.
pconvex_structure pyramid_Q2_incomplete_structure()
Give a pointer on the 3D quadratic incomplete pyramid structure.
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:72
pconvex_structure pyramid_QK_structure(dim_type k)
Give a pointer on the 3D pyramid structure for a degree k = 1 or 2.
std::string name_of_geometric_trans(pgeometric_trans p)
Get the string name of a geometric transformation.
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)
pconvex_ref simplex_of_reference(dim_type nc, short_type K)
returns a simplex of reference of dimension nc and degree k
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
pconvex_structure parallelepiped_structure(dim_type nc, dim_type k)
Give a pointer on the structures of a parallelepiped of dimension d.
pconvex_ref pyramid_Q2_incomplete_of_reference()
incomplete quadratic pyramidal element of reference (13-node)
pconvex_ref prism_incomplete_P2_of_reference()
incomplete quadratic prism element of reference (15-node)
pconvex_structure prism_P1_structure(dim_type nc)
Give a pointer on the structures of a prism of dimension d.
base_matrix compute_local_basis(const geotrans_interpolation_context &c, size_type face)
return the local basis (i.e.
pconvex_structure simplex_structure(dim_type nc)
Give a pointer on the structures of a simplex of dimension d.
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...
pgeometric_trans geometric_trans_descriptor(std::string name)
Get the geometric transformation from its string name.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48
pconvex_ref Q2_incomplete_of_reference(dim_type nc)
incomplete Q2 quadrilateral/hexahedral of reference of dimension d = 2 or 3
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
Dynamic Array Library.
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.
void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored)
Delete an object and the object which depend on it.
pstatic_stored_object search_stored_object(pstatic_stored_object_key k)
Gives a pointer to an object from a key pointer.
An adaptor that adapts a two dimensional geometric_trans to include radial dimension.
Definition: bgeot_torus.h:47