HArD::Core3D
Hybrid Arbitrary Degree::Core 3D - Library to implement 3D schemes with vertex, edge, face and cell polynomials as unknowns
IntegrateTripleProduct.hpp
Go to the documentation of this file.
1 #ifndef INTEGRATE_TRIPLE_PRODUCT_HPP
2 #define INTEGRATE_TRIPLE_PRODUCT_HPP
3 
4 #include <GMpoly_cell.hpp>
5 
6 namespace HArDCore3D {
7 
13 typedef boost::multi_array<double, 3> Scalar3Tensor;
14 typedef Eigen::Map<Eigen::MatrixXd, Eigen::Unaligned, Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> MatrixSlice;
15 typedef Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<Eigen::Dynamic>> VectorSlice;
16 
17 //----------------------------------------------------------------------
18 //----------------------------------------------------------------------
19 // FUNCTIONS TO SLICE SCALAR 3_TENSORS
20 //----------------------------------------------------------------------
21 //----------------------------------------------------------------------
22 
23 //
25 
29  Scalar3Tensor & tensor,
30  size_t fixed_dim,
31  size_t index
32  )
33 {
34  size_t size_dim1 = tensor.shape()[0];
35  size_t size_dim2 = tensor.shape()[1];
36  size_t size_dim3 = tensor.shape()[2];
37 
38  size_t start;
39  size_t num_rows;
40  size_t num_cols;
41  size_t column_stride; // no. elements between two column entries
42  size_t row_stride; // no. elements between two row entries
43 
44  if (fixed_dim == 1 && index < size_dim1){
45  start = index*size_dim2*size_dim3;
46  num_rows = size_dim2;
47  num_cols = size_dim3;
48  column_stride = 1;
49  row_stride = size_dim3;
50  } else if (fixed_dim == 2 && index < size_dim2){
51  start = index*size_dim3;
52  num_rows = size_dim1;
53  num_cols = size_dim3;
54  column_stride = 1;
55  row_stride = size_dim2*size_dim3;
56  } else if (fixed_dim == 3 && index < size_dim3){
57  // Note: this map can be slow in calculations possibly due to the the spacing of the data (non-contiguous in either index), try using a copy if tests are slow.
58  start = index;
59  num_rows = size_dim1;
60  num_cols = size_dim2;
61  column_stride = size_dim3;
62  row_stride = size_dim2*size_dim3;
63  } else{
64  std::cerr << "[IntegrateTripleProduct] ERROR: Multiarray slicing dimension or index out of range" << std::endl;
65  exit(1);
66  }
67 return MatrixSlice(tensor.data() + start, num_rows, num_cols, Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>(column_stride, row_stride));
68 };
69 
71 
73  Scalar3Tensor & tensor,
74  size_t fixed_dim1,
75  size_t index1,
76  size_t fixed_dim2,
77  size_t index2
78  )
79 {
80  size_t size_dim1 = tensor.shape()[0];
81  size_t size_dim2 = tensor.shape()[1];
82  size_t size_dim3 = tensor.shape()[2];
83 
84  size_t start;
85  size_t num_elements;
86  size_t stride; // no. elements between two entries
87 
88  if (fixed_dim1 == 1 && index1 < size_dim1 && fixed_dim2 == 2 && index2 < size_dim2){
89  start = index1*size_dim2*size_dim3 + index2*size_dim3;
90  num_elements = size_dim3;
91  stride = 1;
92  } else if (fixed_dim1 == 2 && index1 < size_dim2 && fixed_dim2 == 1 && index2 < size_dim1){
93  start = index2*size_dim2*size_dim3 + index1*size_dim3;
94  num_elements = size_dim3;
95  stride = 1;
96  } else if (fixed_dim1 == 1 && index1 < size_dim1 && fixed_dim2 == 3 && index2 < size_dim3){
97  start = index1*size_dim2*size_dim3 + index2;
98  num_elements = size_dim2;
99  stride = size_dim3;
100  } else if (fixed_dim1 == 3 && index1 < size_dim3 && fixed_dim2 == 1 && index2 < size_dim1){
101  start = index1 + index2*size_dim2*size_dim3;
102  num_elements = size_dim2;
103  stride = size_dim3;
104  } else if (fixed_dim1 == 2 && index1 < size_dim2 && fixed_dim2 == 3 && index2 < size_dim3){
105  start = index1*size_dim3 + index2;
106  num_elements = size_dim1;
107  stride = size_dim2*size_dim3;
108  } else if (fixed_dim1 == 3 && index1 < size_dim3 && fixed_dim2 == 2 && index2 < size_dim2) {
109  start = index1 + index2*size_dim3;
110  num_elements = size_dim1;
111  stride = size_dim2*size_dim3;
112  }else{
113  std::cerr << "[IntegrateTripleProduct] ERROR: Multiarray slicing dimension or index out of range" << std::endl;
114  exit(1);
115  }
116  return VectorSlice(tensor.data()+start, num_elements, Eigen::InnerStride<>(stride));
117 };
118 
119 //----------------------------------------------------------------------
120 //----------------------------------------------------------------------
121 // FUNCTIONS TO COMPUTE TRIPLE INTEGRALS
122 //----------------------------------------------------------------------
123 //----------------------------------------------------------------------
124 
125 //
126 /* BASIC ONES: Monomial, tensorized, and generic template */
127 
129 template<size_t N>
131  const Cell& T,
132  const MonomialScalarBasisCell & basis1,
134  MonomialCellIntegralsType mono_int_map = {}
135  )
136  {
137  size_t dim1 = basis1.dimension();
138  size_t dim2 = basis2.dimension();
139  size_t anc_dim2 = basis2.ancestor().dimension();
140 
141  size_t totaldegree = basis1.max_degree()+basis2.ancestor().max_degree()+basis2.ancestor().max_degree();
142  Scalar3Tensor scalar_integrals(boost::extents[dim1][anc_dim2][anc_dim2]);
143 
144  // Obtain integration data from IntegrateCellMonomials
145  MonomialCellIntegralsType intmap = CheckIntegralsDegree(T, totaldegree, mono_int_map);
146 
147  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
148  std::fill_n(integrals.data(), integrals.num_elements(), 0);
149 
150  for (size_t i = 0; i < dim1; i++) {
151  for (size_t j = 0; j < anc_dim2; j++) {
152  for (size_t k = 0; k <= j; k++) {
153  scalar_integrals[i][j][k] = intmap.at(basis1.powers(i) + basis2.ancestor().powers(j) + basis2.ancestor().powers(k));
154  scalar_integrals[i][k][j] = scalar_integrals[i][j][k];
155  }
156  }
157  }
158 
159  for (size_t i = 0; i < N; i++){
160  integrals[boost::indices[boost::multi_array_types::index_range(0,dim1)][boost::multi_array_types::index_range(i*anc_dim2,i*anc_dim2+anc_dim2)][boost::multi_array_types::index_range(i*anc_dim2,i*anc_dim2+anc_dim2)]] = scalar_integrals;
161  }
162 
163  return integrals;
164  };
165 
167 template<size_t N>
169  const Cell& T,
172  MonomialCellIntegralsType mono_int_map = {}
173  )
174  {
175  size_t dim1 = tens_family1.dimension();
176  size_t anc_dim1 = tens_family1.ancestor().dimension();
177  size_t dim2 = tens_family2.dimension();
178  size_t anc_dim2 = tens_family2.ancestor().dimension();
179  size_t totaldegree = tens_family1.ancestor().max_degree() + tens_family2.ancestor().max_degree() + tens_family2.ancestor().max_degree();
180 
181  // Obtain integration data from IntegrateCellMonomials
182  MonomialCellIntegralsType intmap = CheckIntegralsDegree(T, totaldegree, mono_int_map);
183 
184  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
185  std::fill_n(integrals.data(), integrals.num_elements(), 0);
186 
187  Eigen::Matrix3i id = Eigen::Matrix3i::Identity();
188 
189  // Loop over the basis vectors: e_i . (e_j x e_k)
190  for (size_t i = 0; i < N; i++){
191  for (size_t j = 0; j < N; j++){
192  for (size_t k = 0; k < j; k++){
193  int sign = id.col(i).dot(id.col(j).cross(id.col(k)));
194  if (sign){
195  // Loop over the monomials
196  for (size_t sub_i = 0; sub_i < anc_dim1; sub_i++){
197  for (size_t sub_j = 0; sub_j < anc_dim2; sub_j++){
198  for (size_t sub_k = 0; sub_k < anc_dim2; sub_k++){
199  integrals[i*anc_dim1 + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] =
200  sign * intmap.at(
201  tens_family1.ancestor().powers(sub_i)
202  + tens_family2.ancestor().powers(sub_j)
203  + tens_family2.ancestor().powers(sub_k)
204  );
205  if (sub_j != sub_k){
206  integrals[i*anc_dim1 + sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[i*anc_dim1 + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
207  }
208  integrals[i*anc_dim1 + sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[i*anc_dim1 + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
209  integrals[i*anc_dim1 + sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[i*anc_dim1 + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
210  }// for sub_k
211  }// for sub_j
212  }// for sub_i
213  };
214  }// for k
215  }// for j
216  }// for i
217  return integrals;
218  };
219 
221 template<size_t N>
223  const Cell& T,
224  const GradientBasis<MonomialScalarBasisCell> & grad_basis,
226  MonomialCellIntegralsType mono_int_map = {}
227  )
228  {
229  size_t dim1 = grad_basis.dimension();
230  size_t dim2 = tens_family.dimension();
231  size_t anc_dim2 = tens_family.ancestor().dimension();
232  size_t totaldegree = grad_basis.ancestor().max_degree()-1 + tens_family.ancestor().max_degree() + tens_family.ancestor().max_degree();
233 
234  // Obtain integration data from IntegrateCellMonomials
235  MonomialCellIntegralsType intmap = CheckIntegralsDegree(T, totaldegree, mono_int_map);
236 
237  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
238  std::fill_n(integrals.data(), integrals.num_elements(), 0);
239 
240  Eigen::Matrix3i id = Eigen::Matrix3i::Identity();
241 
242  // Loop over the basis vectors: e_i . (e_j x e_k)
243  for (size_t i = 0; i < N; i++){
244  for (size_t j = 0; j < N; j++){
245  for (size_t k = 0; k < j; k++){
246  int sign = id.col(i).dot(id.col(j).cross(id.col(k)));
247  if (sign){
248  // Loop over the monomials
249  for (size_t sub_i = 0; sub_i < dim1; sub_i++){
250  if (grad_basis.ancestor().powers(sub_i)[i]>0){
251  for (size_t sub_j = 0; sub_j < anc_dim2; sub_j++){
252  for (size_t sub_k = 0; sub_k < anc_dim2; sub_k++){
253  integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] =
254  sign * grad_basis.ancestor().powers(sub_i)[i]
255  * intmap.at(
256  grad_basis.ancestor().powers(sub_i)-id.col(i)
257  + tens_family.ancestor().powers(sub_j)
258  + tens_family.ancestor().powers(sub_k)
259  ) / T.diam();
260  if (sub_j != sub_k){
261  integrals[sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
262  }
263  integrals[sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
264  integrals[sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
265  }// for sub_k
266  }// for sub_j
267  };
268  }// for sub_i
269  };
270  }// for k
271  }// for j
272  }// for i
273  return integrals;
274  };
275 
277 template<size_t N>
279  const Cell& T,
280  const GolyComplBasisCell & golycompl_basis,
282  MonomialCellIntegralsType mono_int_map = {}
283  )
284  {
285  size_t dim1 = golycompl_basis.dimension();
286  size_t dimPkmo = golycompl_basis.dimPkmo();
287  size_t dimPkmo2 = dim1 - 2*dimPkmo;
288  size_t dim2 = tens_family.dimension();
289 
290  size_t anc_dim2 = tens_family.ancestor().dimension();
291  size_t totaldegree = golycompl_basis.max_degree()+ tens_family.ancestor().max_degree() + tens_family.ancestor().max_degree();
292 
293  // Obtain integration data from IntegrateCellMonomials
294  MonomialCellIntegralsType intmap = CheckIntegralsDegree(T, totaldegree, mono_int_map);
295 
296  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
297  std::fill_n(integrals.data(), integrals.num_elements(), 0);
298 
299  Eigen::Matrix3i id = Eigen::Matrix3i::Identity();
300 
301  // Loop over the basis vectors: (e_j x e_k)
302  for (size_t j = 0; j < N; j++){
303  for (size_t k = 0; k < N; k++){
304  Eigen::Vector3i direction = id.col(j).cross(id.col(k));
305  int sign = direction.sum();
306  // Loop over the basis/monomials
307  for (size_t sub_j = 0; sub_j < anc_dim2; sub_j++){
308  for (size_t sub_k = 0; sub_k <= sub_j; sub_k++){
309  if (direction==id.col(0)){
310  // Second direction of golycompl
311  for (size_t sub_i = 0; sub_i < dimPkmo; sub_i++){
312  integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] = -sign * intmap.at(golycompl_basis.powers(dimPkmo + sub_i) + id.col(2) + tens_family.ancestor().powers(sub_j) + tens_family.ancestor().powers(sub_k));
313  integrals[dimPkmo + sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
314  integrals[dimPkmo + sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
315  integrals[dimPkmo + sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
316  }
317  // Third direction of golycompl
318  for (size_t sub_i = 0; sub_i < dimPkmo2; sub_i++){
319  integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] = sign * intmap.at(golycompl_basis.powers(2*dimPkmo + sub_i) + id.col(1) + tens_family.ancestor().powers(sub_j) + tens_family.ancestor().powers(sub_k));
320  integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
321  integrals[2*dimPkmo + sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
322  integrals[2*dimPkmo + sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
323  }
324  }else if (direction==id.col(1)){
325  // First direction of golycompl
326  for (size_t sub_i = 0; sub_i < dimPkmo; sub_i++){
327  integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] = sign * intmap.at(golycompl_basis.powers(sub_i)+ id.col(2) + tens_family.ancestor().powers(sub_j) + tens_family.ancestor().powers(sub_k));
328  integrals[sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
329  integrals[sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
330  integrals[sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
331  }
332  // Third direction of golycompl
333  for (size_t sub_i = 0; sub_i < dimPkmo2; sub_i++){
334  integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] = -sign * intmap.at(golycompl_basis.powers(2*dimPkmo + sub_i) + id.col(0) + tens_family.ancestor().powers(sub_j) + tens_family.ancestor().powers(sub_k));
335  integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
336  integrals[2*dimPkmo + sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
337  integrals[2*dimPkmo + sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[2*dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
338  }
339  }else if (direction==id.col(2)){
340  // First direction of golycompl
341  for (size_t sub_i = 0; sub_i < dimPkmo; sub_i++){
342  integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] = -sign * intmap.at(golycompl_basis.powers(sub_i)+ id.col(1) + tens_family.ancestor().powers(sub_j) + tens_family.ancestor().powers(sub_k));
343  integrals[sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
344  integrals[sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
345  integrals[sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
346  }
347  // Second direction of golycompl
348  for (size_t sub_i = 0; sub_i < dimPkmo; sub_i++){
349  integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k] = sign * intmap.at(golycompl_basis.powers(dimPkmo + sub_i) + id.col(0) + tens_family.ancestor().powers(sub_j) + tens_family.ancestor().powers(sub_k));
350  integrals[dimPkmo + sub_i][j*anc_dim2 + sub_k][k*anc_dim2 + sub_j] = integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
351  integrals[dimPkmo + sub_i][k*anc_dim2 + sub_j][j*anc_dim2 + sub_k] = -integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
352  integrals[dimPkmo + sub_i][k*anc_dim2 + sub_k][j*anc_dim2 + sub_j] = -integrals[dimPkmo + sub_i][j*anc_dim2 + sub_j][k*anc_dim2 + sub_k];
353  }
354  } //else
355  }// for sub_k
356  }// for sub_j
357  }// for k
358  }// for j
359  return integrals;
360  };
361 
362 //----------------------------------------------------------------------
363 // Family, Shift, Tensorized
364 
365 template<typename ScalarBasisType1, typename ScalarBasisType2, size_t N>
367  const Cell& T,
368  const GradientBasis<ShiftedBasis<ScalarBasisType1>> & grad_shift_basis,
370  MonomialCellIntegralsType mono_int_map = {}
371  )
372  {
373  size_t dim2 = basis2.dimension();
374  size_t unshifted_dim1 = grad_shift_basis.ancestor().ancestor().dimension();
375  size_t shift = grad_shift_basis.ancestor().shift();
376 
377  GradientBasis<ScalarBasisType1> grad_basis(grad_shift_basis.ancestor().ancestor());
378 
379  Scalar3Tensor anc_integrals = tripleInt(T, grad_basis, basis2, mono_int_map);
380 
381  Scalar3Tensor integrals = anc_integrals[boost::indices[boost::multi_array_types::index_range(shift,unshifted_dim1)][boost::multi_array_types::index_range(0,dim2)][boost::multi_array_types::index_range(0,dim2)]];
382 
383  return integrals;
384  };
385 
386 template<typename ScalarBasisType, typename BasisType>
388  const Cell& T,
389  const GradientBasis<ShiftedBasis<ScalarBasisType>> & grad_shift_basis,
390  const BasisType & basis2,
391  MonomialCellIntegralsType mono_int_map = {}
392  )
393  {
394  size_t dim2 = basis2.dimension();
395  size_t unshifted_dim1 = grad_shift_basis.ancestor().ancestor().dimension();
396  size_t shift = grad_shift_basis.ancestor().shift();
397 
398  GradientBasis<ScalarBasisType> grad_basis(grad_shift_basis.ancestor().ancestor());
399 
400  Scalar3Tensor anc_integrals = tripleInt(T, grad_basis, basis2, mono_int_map);
401 
402  Scalar3Tensor integrals = anc_integrals[boost::indices[boost::multi_array_types::index_range(shift,unshifted_dim1)][boost::multi_array_types::index_range(0,dim2)][boost::multi_array_types::index_range(0,dim2)]];
403 
404  return integrals;
405  };
406 
407 template<typename BasisType, typename ScalarBasisType, size_t N>
409  const Cell& T,
410  const BasisType & basis1,
412  MonomialCellIntegralsType mono_int_map = {}
413  )
414  {
415  size_t dim1 = basis1.dimension();
416  size_t dim2 = basis2.dimension();
417  size_t anc_dim2 = basis2.ancestor().dimension();
418  size_t anc_anc_dim2 = basis2.ancestor().ancestor().dimension();
419 
420  Eigen::MatrixXd M2 = basis2.ancestor().matrix();
421 
422  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
423  std::fill_n(integrals.data(), integrals.num_elements(), 0);
424 
425  TensorizedVectorFamily<ScalarBasisType, N> red_basis2(basis2.ancestor().ancestor());
426 
427  Scalar3Tensor tensor_integrals = tripleInt(T, basis1, red_basis2, mono_int_map);
428 
429  for (size_t j = 0; j < N; j++){
430  for (size_t k = 0; k < N; k++){
431  Scalar3Tensor anc_scalar_integrals = tensor_integrals[boost::indices[boost::multi_array_types::index_range(0,dim1)][boost::multi_array_types::index_range(j*anc_anc_dim2,(j+1)*anc_anc_dim2)][boost::multi_array_types::index_range(k*anc_anc_dim2,(k+1)*anc_anc_dim2)]];
432  for (size_t i = 0; i < dim1; i++){
433  MatrixSlice int_jk = slice(anc_scalar_integrals, 1, i);
434  for (size_t sub_j = 0; sub_j < anc_dim2; sub_j++){
435  for (size_t sub_k = 0; sub_k <= sub_j; sub_k++){
436  integrals[i][anc_dim2*j + sub_j][anc_dim2*k + sub_k] = M2.row(sub_j) * int_jk * M2.row(sub_k).transpose();
437  integrals[i][anc_dim2*j + sub_k][anc_dim2*k + sub_j] = integrals[i][anc_dim2*j + sub_j][anc_dim2*k + sub_k];
438  }
439  }
440  }
441  }
442  }
443  return integrals;
444  };
445 
446 template<typename BasisType, typename ScalarBasisType, size_t N>
448  const Cell& T,
449  const Family<BasisType> & basis1,
451  MonomialCellIntegralsType mono_int_map = {}
452  )
453  {
454  size_t dim1 = basis1.dimension();
455  size_t dim2 = basis2.dimension();
456  size_t anc_dim1 = basis1.ancestor().dimension();
457  size_t anc_dim2 = basis2.ancestor().dimension();
458 
459  Eigen::MatrixXd M1 = basis1.matrix();
460  Eigen::MatrixXd M2 = basis2.matrix();
461 
462  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
463  std::fill_n(integrals.data(), integrals.num_elements(), 0);
464 
465  Scalar3Tensor anc_integrals = tripleInt(T, basis1.ancestor(), basis2.ancestor(), mono_int_map);
466 
467  for (size_t i = 0; i < dim1; i++){
468  Eigen::MatrixXd int_jk = Eigen::MatrixXd::Zero(anc_dim2, anc_dim2);
469  for (size_t l = 0; l < anc_dim1; l++){
470  int_jk += M1(i, l) * slice(anc_integrals, 1, l);
471  }
472 
473  for (size_t j = 0; j < dim2; j++){
474  for (size_t k = 0; k < dim2; k++){
475  integrals[i][j][k] = M2.row(j) * int_jk * M2.row(k).transpose();
476  }
477  }
478  }
479  return integrals;
480  };
481 
482 template<typename BasisType, size_t N>
484  const Cell& T,
485  const Family<BasisType> & basis1,
487  MonomialCellIntegralsType mono_int_map = {}
488  )
489  {
490  size_t dim1 = basis1.dimension();
491  size_t dim2 = basis2.dimension();
492  size_t anc_dim1 = basis1.ancestor().dimension();
493 
494  Eigen::MatrixXd M1 = basis1.matrix();
495 
496  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
497  std::fill_n(integrals.data(), integrals.num_elements(), 0);
498 
499  Scalar3Tensor scalar_integrals = tripleInt(T, basis1.ancestor(), basis2, mono_int_map);
500 
501  for (size_t i = 0; i < dim1; i++){
502  MatrixSlice int_jk = slice(integrals, 1, i);
503  for (size_t l = 0; l < anc_dim1; l++){
504  int_jk += M1(i, l) * slice(scalar_integrals, 1, l);
505  }
506  }
507  return integrals;
508  };
509 
510 template<typename BasisType1, typename BasisType2>
512  const Cell& T,
513  const BasisType1 & basis1,
514  const Family<BasisType2> & basis2,
515  MonomialCellIntegralsType mono_int_map = {}
516  )
517  {
518  size_t dim1 = basis1.dimension();
519  size_t dim2 = basis2.dimension();
520 
521  Eigen::MatrixXd M2 = basis2.matrix();
522 
523  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
524  std::fill_n(integrals.data(), integrals.num_elements(), 0);
525 
526  Scalar3Tensor scalar_integrals = tripleInt(T, basis1, basis2.ancestor(), mono_int_map);
527 
528  for (size_t i = 0; i < dim1; i++){
529  MatrixSlice int_jk = slice(scalar_integrals, 1, i);
530  for (size_t j = 0; j < dim2; j++){
531  for (size_t k = 0; k <= j; k++){
532  integrals[i][j][k] = M2.row(j) * int_jk * M2.row(k).transpose();
533  integrals[i][k][j] = integrals[i][j][k];
534  }
535  }
536  }
537  return integrals;
538  };
539 
540 template<size_t N, typename ScalarBasisType>
542  const Cell& T,
543  const TensorizedVectorFamily<Family<ScalarBasisType>, N> & tens_family1,
545  MonomialCellIntegralsType mono_int_map = {}
546  )
547  {
548  size_t dim1 = tens_family1.dimension();
549  size_t anc_dim1 = tens_family1.ancestor().dimension();
550  size_t anc_anc_dim1 = tens_family1.ancestor().ancestor().dimension();
551  size_t dim2 = tens_family2.dimension();
552  size_t anc_dim2 = tens_family2.ancestor().dimension();
553 
554  Eigen::MatrixXd M1 = tens_family1.ancestor().matrix();
555 
556  Scalar3Tensor integrals(boost::extents[dim1][dim2][dim2]);
557  std::fill_n(integrals.data(), integrals.num_elements(), 0);
558 
559  TensorizedVectorFamily<ScalarBasisType, N> red_basis1(tens_family1.ancestor().ancestor());
560 
561  Scalar3Tensor tensor_integrals = tripleInt(T, red_basis1, tens_family2, mono_int_map);
562  Eigen::Matrix3i id = Eigen::Matrix3i::Identity();
563  // Loop over the basis vectors: e_i . (e_j x e_k)
564  for (size_t i = 0; i < N; i++){
565  for (size_t j = 0; j < N; j++){
566  for (size_t k = 0; k < j; k++){
567  int sign = id.col(i).dot(id.col(j).cross(id.col(k)));
568  if (sign){
569  Scalar3Tensor anc_scalar_integrals = tensor_integrals[boost::indices[boost::multi_array_types::index_range(i*anc_anc_dim1,(i+1)*anc_anc_dim1)][boost::multi_array_types::index_range(j*anc_dim2,(j+1)*anc_dim2)][boost::multi_array_types::index_range(k*anc_dim2,(k+1)*anc_dim2)]];
570  for (size_t sub_j = 0; sub_j < anc_dim2; sub_j++){
571  Eigen::MatrixXd fam_int_jk = M1 * slice(anc_scalar_integrals, 2, sub_j);
572  for (size_t sub_i = 0; sub_i < anc_dim1; sub_i++){
573  for (size_t sub_k = 0; sub_k < anc_dim2; sub_k++){
574  integrals[i*anc_dim1+sub_i][j*anc_dim2+sub_j][k*anc_dim2+sub_k] = fam_int_jk(sub_i, sub_k);
575  integrals[i*anc_dim1+sub_i][k*anc_dim2+sub_j][j*anc_dim2+sub_k] = -fam_int_jk(sub_i, sub_k);
576  }
577  }
578  }
579  };
580  }// for k
581  }// for j
582  }// for i
583  return integrals;
584  };
585 }
586 
587 #endif
Family of functions expressed as linear combination of the functions of a given basis.
Definition: basis.hpp:388
Basis for the complement G^{c,k}(T) in P^k(T)^3 of the range of grad.
Definition: basis.hpp:1503
Basis for the space of gradients of polynomials.
Definition: basis.hpp:1228
Scalar monomial basis on a cell.
Definition: basis.hpp:154
Generate a basis where the function indices are shifted.
Definition: basis.hpp:1012
Vector family obtained by tensorization of a scalar family.
Definition: basis.hpp:609
constexpr const BasisType & ancestor() const
Return the ancestor.
Definition: basis.hpp:564
size_t dimPkmo() const
Returns the dimension of P^{k-1}(R^3)
Definition: basis.hpp:1553
size_t dimension() const
Return the dimension of the family.
Definition: basis.hpp:640
constexpr const ScalarFamilyType & ancestor() const
Return the ancestor (family that has been tensorized)
Definition: basis.hpp:747
VectorZd powers(size_t i) const
Returns the powers of the i-th basis function (its degree can be found using powers(i)....
Definition: basis.hpp:201
size_t dimension() const
Compute the dimension of the basis.
Definition: basis.hpp:1529
VectorZd powers(size_t i) const
Returns the powers of the i-th basis function (not including the vector part)
Definition: basis.hpp:1547
constexpr const BasisType & ancestor() const
Return the ancestor (basis that the gradient was taken of)
Definition: basis.hpp:1273
size_t dimension() const
Dimension of the family. This is actually the number of functions in the family, not necessarily line...
Definition: basis.hpp:421
size_t max_degree() const
Returns the maximum degree of the basis functions.
Definition: basis.hpp:195
size_t dimension() const
Compute the dimension of the basis.
Definition: basis.hpp:180
size_t dimension() const
Compute the dimension of the basis.
Definition: basis.hpp:1261
size_t max_degree() const
Returns the maximum degree of the basis functions.
Definition: basis.hpp:1541
const Eigen::MatrixXd & matrix() const
Return the coefficient matrix.
Definition: basis.hpp:558
boost::multi_array< double, 3 > Scalar3Tensor
Definition: IntegrateTripleProduct.hpp:13
Scalar3Tensor tripleInt(const Cell &T, const MonomialScalarBasisCell &basis1, const TensorizedVectorFamily< MonomialScalarBasisCell, N > &basis2, MonomialCellIntegralsType mono_int_map={})
Computes the triple integral product of a scalar times the dot product of two vectors - basis1(basis2...
Definition: IntegrateTripleProduct.hpp:130
MonomialCellIntegralsType CheckIntegralsDegree(const Cell &T, const size_t degree, const MonomialCellIntegralsType &mono_int_map={})
Checks if the degree of an existing list of monomial integrals is sufficient, other re-compute and re...
Definition: GMpoly_cell.cpp:160
Eigen::Map< Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride< Eigen::Dynamic > > VectorSlice
Definition: IntegrateTripleProduct.hpp:15
MatrixSlice slice(Scalar3Tensor &tensor, size_t fixed_dim, size_t index)
Function to slice a 3-tensor with respect to one index (returns a 2-tensor)
Definition: IntegrateTripleProduct.hpp:28
Eigen::Map< Eigen::MatrixXd, Eigen::Unaligned, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > MatrixSlice
Definition: IntegrateTripleProduct.hpp:14
std::unordered_map< VectorZd, double, VecHash > MonomialCellIntegralsType
Type for list of integrals of monomials.
Definition: GMpoly_cell.hpp:49
Definition: ddr-magnetostatics.hpp:40
MeshND::Cell< 2 > Cell
Definition: Mesh2D.hpp:13