1 #ifndef _PVFMM_CHEB_UTILS_HPP_ 2 #define _PVFMM_CHEB_UTILS_HPP_ 4 #include <pvfmm/kernel.hpp> 5 #include <pvfmm/matrix.hpp> 6 #include <pvfmm/vector.hpp> 7 #include <pvfmm/common.hpp> 8 #include <pvfmm/legendre_rule.hpp> 10 #include <type_traits> 17 template <Integer DIM>
static void Nodes(Integer order,
Vector<ValueType>& nodes) {
19 Derived::Nodes1D(order, nodes);
24 Derived::Nodes1D(order, nodes1d);
26 Integer order_DIM = pvfmm::pow<Integer>(order, DIM);
27 if (nodes.Dim() != order_DIM * DIM) nodes.ReInit(order_DIM * DIM);
29 StaticArray<Integer, DIM> idx;
30 for (Integer i = 0; i < DIM; i++) idx[i] = 0;
32 for (Integer j = 0; j < order_DIM; j++) {
33 for (Integer i = 0; i < DIM; i++) {
34 if (idx[i] == order) idx[i] = 0;
35 nodes[itr + i] = nodes1d[idx[i]];
39 for (Integer i = 1; i < DIM; i++) {
40 if (idx[i - 1] == order) idx[i]++;
54 PVFMM_ASSERT(order < precomp.Dim());
55 if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
56 #pragma omp critical(BASIS_APPROX) 57 if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
59 Derived::Nodes1D(order, x);
60 Derived::EvalBasis1D(order, x, p);
62 Mp1.pinv().Swap(precomp[order]);
65 Mp.ReInit(precomp[order].Dim(0), precomp[order].Dim(1), precomp[order].Begin(),
false);
68 Integer order_DIM = pvfmm::pow<Integer>(order, DIM);
69 Integer order_DIM_ = pvfmm::pow<Integer>(order, DIM - 1);
70 Long dof = fn_v.Dim() / order_DIM;
71 PVFMM_ASSERT(fn_v.Dim() == dof * order_DIM);
74 Long buff_size = dof * order_DIM;
76 Iterator<ValueType> buff1 = buff.Begin() + buff_size * 0;
77 Iterator<ValueType> buff2 = buff.Begin() + buff_size * 1;
80 for (Integer k = 0; k < DIM; k++) {
86 for (Long i = 0; i < Mo.Dim(0); i++) {
87 for (Long j = 0; j < Mo.Dim(1); j++) {
88 Mo_t[j][i] = Mo[i][j];
91 fn.ReInit(order_DIM * dof, buff1,
false);
96 tensor2coeff<DIM>(order, tensor, coeff);
104 PVFMM_ASSERT(order < precomp.Dim());
105 if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
106 #pragma omp critical(BASIS_APPROX) 107 if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
109 Derived::Nodes1D(order, x);
110 for (Integer i = 0; i < order; i++) x[i] = (x[i] - 0.5) * scale + 0.5;
111 Derived::EvalBasis1D(order, x, p);
113 Mp1.pinv().Swap(precomp[order]);
116 Mp.ReInit(precomp[order].Dim(0), precomp[order].Dim(1), precomp[order].Begin(),
false);
119 Integer order_DIM = pvfmm::pow<Integer>(order, DIM);
120 Integer order_DIM_ = pvfmm::pow<Integer>(order, DIM - 1);
121 Long dof = fn_v.Dim() / order_DIM;
122 PVFMM_ASSERT(fn_v.Dim() == dof * order_DIM);
125 Long buff_size = dof * order_DIM;
127 Iterator<ValueType> buff1 = buff.Begin() + buff_size * 0;
128 Iterator<ValueType> buff2 = buff.Begin() + buff_size * 1;
131 for (Integer k = 0; k < DIM; k++) {
137 for (Long i = 0; i < Mo.Dim(0); i++) {
138 for (Long j = 0; j < Mo.Dim(1); j++) {
139 Mo_t[j][i] = Mo[i][j];
142 fn.ReInit(order_DIM * dof, buff1,
false);
147 tensor2coeff<DIM>(order, tensor, coeff);
159 for (Integer i = 0; i < DIM; i++) {
160 Ncoeff = (Ncoeff * (order + i)) / (i + 1);
162 Long dof = coeff.Dim() / Ncoeff;
163 PVFMM_ASSERT(coeff.Dim() == Ncoeff * dof);
166 Long buff_size = dof;
167 StaticArray<Matrix<ValueType>, DIM> Mp;
168 for (Integer i = 0; i < DIM; i++) {
169 Integer n = in_x[i].Dim();
171 Mp[i].ReInit(order, n);
173 Derived::EvalBasis1D(order, in_x[i], p);
174 buff_size *= std::max(order, n);
179 Iterator<ValueType> buff1 = buff.Begin() + buff_size * 0;
180 Iterator<ValueType> buff2 = buff.Begin() + buff_size * 1;
184 coeff2tensor<DIM>(order, coeff, tensor);
189 for (Integer i = 0; i < DIM; i++) len *= in_x[i].Dim();
190 if (out.Dim() != len) out.ReInit(len);
193 for (Integer k = 0; k < DIM; k++) {
194 Integer order_DIM = pvfmm::pow<Integer>(order, DIM - k - 1);
195 for (Integer i = 0; i < k; i++) order_DIM *= in_x[i].Dim();
202 if (k == DIM - 1) Mo_t.ReInit(in_x[k].Dim(), dof * order_DIM, out.Begin(),
false);
203 for (Long i = 0; i < Mo.Dim(0); i++) {
204 for (Long j = 0; j < Mo.Dim(1); j++) {
205 Mo_t[j][i] = Mo[i][j];
219 for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
221 Long dof = coeff.Dim() / Ncoeff;
222 PVFMM_ASSERT(coeff.Dim() == Ncoeff * dof);
225 for (Long l = 0; l < dof; l++) {
226 Long offset0 = l * Ncoeff;
230 StaticArray<Integer, DIM + 1> i0;
231 for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
236 if (sum == order - 1) err += pvfmm::fabs<ValueType>(coeff[offset0 + indx0]);
243 for (Integer j = 0; j < DIM && i0[j] == order; j++) {
246 sum = sum + 1 - order;
262 for (Integer i = 0; i < DIM; i++) {
263 Ncoeff = (Ncoeff * (order + i)) / (i + 1);
265 Long dof = coeff_in.Dim() / Ncoeff;
266 PVFMM_ASSERT(coeff_in.Dim() == Ncoeff * dof);
271 PVFMM_ASSERT(order < precomp.Dim());
272 if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
273 #pragma omp critical(BASIS_GRAD) 274 if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
277 M.Swap(precomp[order]);
280 Mdiff.ReInit(precomp[order].Dim(0), precomp[order].Dim(1), precomp[order].Begin(),
false);
284 Long buff_size = dof * pvfmm::pow<Integer>(order, DIM);
292 coeff2tensor<DIM>(order, coeff_in, buff0);
295 for (Integer k = 0; k < DIM; k++) {
296 Long N0 = pvfmm::pow<Integer>(order, k);
298 Long N2 = pvfmm::pow<Integer>(order, DIM - k - 1);
300 for (Long i3 = 0; i3 < dof; i3++) {
301 for (Long i2 = 0; i2 < N2; i2++) {
302 for (Long i1 = 0; i1 < N1; i1++) {
303 for (Long i0 = 0; i0 < N0; i0++) {
304 buff1[((i3 * N2 + i2) * N0 + i0) * N1 + i1] = buff0[((i3 * N2 + i2) * N1 + i1) * N0 + i0];
316 for (Long i3 = 0; i3 < dof; i3++) {
317 for (Long i2 = 0; i2 < N2; i2++) {
318 for (Long i1 = 0; i1 < N1; i1++) {
319 for (Long i0 = 0; i0 < N0; i0++) {
320 buff3[(((i2 * N1 + i1) * N0 + i0) * dof + i3) * DIM + k] = buff2[((i3 * N2 + i2) * N0 + i0) * N1 + i1];
328 tensor2coeff<DIM>(order, buff3, *coeff_out);
332 template <Integer DIM, Integer SUBDIM>
static void Integ(
Matrix<ValueType>& Mcoeff, Integer order, ConstIterator<ValueType> trg_, ValueType side, Integer src_face,
const KernelFunction<ValueType, DIM>& ker, ValueType tol = -1, Integer Nq = 0) {
334 Integ_<DIM, SUBDIM>(Mcoeff, order, trg_, side, src_face, ker, Nq);
335 if (tol < 0) tol = 1e-10;
336 ValueType err = tol + 1;
340 ValueType max_val = pvfmm::pow<SUBDIM>(side);
341 Nq = std::max((Integer)(Nq * 1.26), Nq + 1);
342 Integ_<DIM, SUBDIM>(Mtmp, order, trg_, side, src_face, ker, Nq);
343 for (Integer i = 0; i < Mtmp.Dim(0) * Mtmp.Dim(1); i++) {
344 err = std::max(err, pvfmm::fabs<ValueType>(Mtmp[0][i] - Mcoeff[0][i]));
345 max_val = std::max(max_val, pvfmm::fabs<ValueType>(Mtmp[0][i]));
350 PVFMM_WARN(
"Failed to converge, error = "<<err);
354 Mcoeff = Mcoeff.Transpose();
358 Integer Ncoeff = 1, Ntensor = pvfmm::pow<Integer>(order, DIM);
359 for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
360 Long dof = tensor.Dim() / Ntensor;
361 PVFMM_ASSERT(tensor.Dim() == Ntensor * dof);
362 if (coeff.Dim() != Ncoeff * dof) coeff.ReInit(Ncoeff * dof);
364 for (Long l = 0; l < dof; l++) {
365 Long offset0 = l * Ncoeff;
369 StaticArray<Integer, DIM + 1> i0;
370 for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
375 coeff[offset0 + indx0] = tensor[l + indx1 * dof];
382 for (Integer j = 0; j < DIM && i0[j] == order; j++) {
385 sum = sum + 1 - order;
393 Integer Ncoeff = 1, Ntensor = pvfmm::pow<Integer>(order, DIM);
394 for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
395 Long dof = coeff.Dim() / Ncoeff;
396 PVFMM_ASSERT(coeff.Dim() == Ncoeff * dof);
397 if (tensor.Dim() != Ntensor * dof) tensor.ReInit(Ntensor * dof);
399 for (Long l = 0; l < dof; l++) {
400 Long offset0 = l * Ncoeff;
401 Long offset1 = l * Ntensor;
405 StaticArray<Integer, DIM + 1> i0;
406 for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
411 tensor[offset1 + indx1] = coeff[offset0 + indx0];
414 tensor[offset1 + indx1] = 0;
420 for (Integer j = 0; j < DIM && i0[j] == order; j++) {
423 sum = sum + 1 - order;
430 template <Integer DIM>
static void Truncate(
Vector<ValueType> &coeff0, Integer order0, Integer order1) {
431 PVFMM_ASSERT(order1 <= order0);
432 Integer Ncoeff0 = 1, Ncoeff1 = 1;
433 for (Integer i = 0; i < DIM; i++) Ncoeff0 = (Ncoeff0 * (order0 + i)) / (i + 1);
434 for (Integer i = 0; i < DIM; i++) Ncoeff1 = (Ncoeff1 * (order1 + i)) / (i + 1);
436 Long dof = coeff0.Dim() / Ncoeff0;
437 PVFMM_ASSERT(coeff0.Dim() == Ncoeff0 * dof);
441 for (Long l = 0; l < dof; l++) {
442 Long offset0 = l * Ncoeff0;
443 Long offset1 = l * Ncoeff1;
447 StaticArray<Integer, DIM + 1> i0;
448 for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
452 if (sum < order1) coeff1[offset1 + indx1] = coeff0[offset0 + indx0];
453 if (sum < order0) indx0++;
454 if (sum < order1) indx1++;
458 for (Integer j = 0; j < DIM && i0[j] == order0; j++) {
461 sum = sum + 1 - order0;
469 template <Integer DIM>
static void Reflect(
Vector<ValueType> &coeff, Integer order, Integer dir) {
470 PVFMM_ASSERT(dir < DIM);
472 for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
474 Long dof = coeff.Dim() / Ncoeff;
475 PVFMM_ASSERT(coeff.Dim() == Ncoeff * dof);
477 for (Long l = 0; l < dof; l++) {
478 Long offset = l * Ncoeff;
481 StaticArray<Integer, DIM + 1> i0;
482 for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
486 if (sum < order) coeff[offset + indx] = coeff[offset + indx] * (i0[dir] % 2 ? -1 : 1) * (1);
487 if (sum < order) indx++;
491 for (Integer j = 0; j < DIM && i0[j] == order; j++) {
494 sum = sum + 1 - order;
501 template <Integer DIM, Integer CONTINUITY>
static void MakeContinuous(
Vector<ValueType> &coeff0,
Vector<ValueType> &coeff1, Integer order, Integer dir0, Integer dir1) {
502 if (dir0>=2*DIM || dir1>=2*DIM)
return;
504 for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
506 Long dof = coeff0.Dim() / Ncoeff;
507 PVFMM_ASSERT(coeff0.Dim() == Ncoeff * dof);
508 PVFMM_ASSERT(coeff1.Dim() == Ncoeff * dof);
511 if (M[dir0][dir1].Dim(0) != 2 * Ncoeff) {
512 Integer Ngrid = pvfmm::pow<Integer>(order, DIM - 1);
514 Nodes<1>(order, nodes);
519 StaticArray<Vector<ValueType>, DIM> nodes_;
520 for (Integer i = 0; i < DIM; i++) {
521 nodes_[i].ReInit(nodes.Dim(), nodes.Begin(),
false);
530 for (Integer i = 0; i < Ncoeff; i++) {
532 value.ReInit(Ngrid, M_diff[i + Ncoeff * 0],
false);
533 nodes_[dir0/2].ReInit(1, (dir0 & 1 ? nodes1.Begin() : nodes0.Begin()),
false);
534 Eval<DIM>(order, coeff, nodes_, value);
535 nodes_[dir0/2].ReInit(nodes.Dim(), nodes.Begin(),
false);
538 value.ReInit(Ngrid, M_diff[i + Ncoeff * 1],
false);
539 nodes_[dir1/2].ReInit(1, (dir1 & 1 ? nodes1.Begin() : nodes0.Begin()),
false);
540 Eval<DIM>(order, coeff, nodes_, value);
541 nodes_[dir1/2].ReInit(nodes.Dim(), nodes.Begin(),
false);
552 for(Integer i = 0; i < Ncoeff; i++) coeff[i * Ncoeff + i] = 1;
553 Grad<DIM>(order, coeff, &coeff_grad);
554 for (Integer i = 0; i < Ncoeff; i++){
555 for (Integer j = 0; j < Ncoeff; j++){
556 M_grad[i + Ncoeff * 0][j + Ncoeff * 0] = coeff_grad[j + (i * DIM + dir0/2) * Ncoeff];
557 M_grad[i + Ncoeff * 1][j + Ncoeff * 1] = coeff_grad[j + (i * DIM + dir1/2) * Ncoeff];
562 auto fn_perturb = [&](std::function<ValueType(ValueType)> fn,
bool even) {
566 Integer N0=pvfmm::pow<Integer>(order, dir0/2);
567 Integer N1=pvfmm::pow<Integer>(order, 1);
568 Integer N2=pvfmm::pow<Integer>(order, DIM - dir0/2 - 1);
569 PVFMM_ASSERT(N0 * N2 == Ngrid);
572 for (Integer i0=0;i0<N0;i0++){
573 for (Integer i2=0;i2<N2;i2++){
574 for (Integer i1=0;i1<N1;i1++){
575 val[(i2*N1+i1)*N0+i0] = (dir0 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1])) * (even ? 1.0 : -1.0);
577 coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 0,
false);
578 Approx<DIM>(order, val, coeff);
579 for (Integer i1=0;i1<N1;i1++){
580 val[(i2*N1+i1)*N0+i0] = 0;
586 Integer N0=pvfmm::pow<Integer>(order, dir1/2);
587 Integer N1=pvfmm::pow<Integer>(order, 1);
588 Integer N2=pvfmm::pow<Integer>(order, DIM - dir1/2 - 1);
589 PVFMM_ASSERT(N0 * N2 == Ngrid);
592 for (Integer i0=0;i0<N0;i0++){
593 for (Integer i2=0;i2<N2;i2++){
594 for (Integer i1=0;i1<N1;i1++){
595 val[(i2*N1+i1)*N0+i0] = (dir1 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1]));
597 coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 1,
false);
598 Approx<DIM>(order, val, coeff);
599 for (Integer i1=0;i1<N1;i1++){
600 val[(i2*N1+i1)*N0+i0] = 0;
608 if (CONTINUITY == 0) {
609 auto fn0 = [](ValueType x) {
return x;};
611 M[dir0][dir1] = M_diff * M0;
612 }
else if (CONTINUITY == 1) {
613 auto fn0 = [](ValueType x) {
return (-2*x + 3) * x * x;};
614 auto fn1 = [](ValueType x) {
return (1 - x) * x * x;};
617 M[dir0][dir1] = M_diff * M0 + M_grad * M_diff * M1;
618 }
else if (CONTINUITY == 2) {
619 auto fn0 = [](ValueType x) {
return x*x*x*(6*x*x-15*x+10);};
620 auto fn1 = [](ValueType x) {
return x*x*x*(-3*x*x+7*x-4);};
621 auto fn2 = [](ValueType x) {
return x*x*x*(0.5*x*x-1*x+0.5);};
625 M[dir0][dir1] = M_diff * M0 + M_grad * M_diff * M1 + M_grad * M_grad * M_diff * M2;
628 for (Integer i=0;i<2*Ncoeff;i++){
629 M[dir0][dir1][i][i]+=1.0;
775 for (Long i = 0; i < dof; i++) {
776 for (Integer j = 0; j < Ncoeff; j++) {
777 x[i][Ncoeff * 0 + j] = coeff0[i * Ncoeff + j];
778 x[i][Ncoeff * 1 + j] = coeff1[i * Ncoeff + j];
782 for (Long i = 0; i < dof; i++) {
783 for (Integer j = 0; j < Ncoeff; j++) {
784 coeff0[i * Ncoeff + j] = y[i][Ncoeff * 0 + j];
785 coeff1[i * Ncoeff + j] = y[i][Ncoeff * 1 + j];
790 template <Integer DIM, Integer CONTINUITY>
static void MakeContinuousEdge(
Vector<ValueType> &coeff0,
Vector<ValueType> &coeff1, Integer order, Integer dir0, Integer dir1, Integer norm0, Integer norm1) {
791 PVFMM_ASSERT(DIM==2);
792 if (dir0>=2*DIM || dir1>=2*DIM)
return;
794 for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
796 Long dof = coeff0.Dim() / Ncoeff;
797 PVFMM_ASSERT(coeff0.Dim() == Ncoeff * dof);
798 PVFMM_ASSERT(coeff1.Dim() == Ncoeff * dof);
802 if (M[dir0][dir1].Dim(0) != 2 * Ncoeff) {
803 Integer Ngrid = pvfmm::pow<Integer>(order, DIM - 1);
805 Nodes<1>(order, nodes);
811 for (Integer i=0;i<order;i++){
812 for (Integer j=0;j<order;j++){
814 w.PushBack(i<order-CONTINUITY*2-1 && j<order-CONTINUITY*2-1);
819 for (Integer i=0;i<Ncoeff;i++){
820 Mtrunc[i + Ncoeff * 0][i + Ncoeff * 0] = w[i];
821 Mtrunc[i + Ncoeff * 1][i + Ncoeff * 1] = w[i];
828 StaticArray<Vector<ValueType>, DIM> nodes_;
829 for (Integer i = 0; i < DIM; i++) {
830 nodes_[i].ReInit(nodes.Dim(), nodes.Begin(),
false);
839 for (Integer i = 0; i < Ncoeff; i++) {
841 value.ReInit(Ngrid, M_diff[i + Ncoeff * 0],
false);
842 nodes_[dir0/2].ReInit(1, (dir0 & 1 ? nodes1.Begin() : nodes0.Begin()),
false);
843 Eval<DIM>(order, coeff, nodes_, value);
844 nodes_[dir0/2].ReInit(nodes.Dim(), nodes.Begin(),
false);
847 value.ReInit(Ngrid, M_diff[i + Ncoeff * 1],
false);
848 nodes_[dir1/2].ReInit(1, (dir1 & 1 ? nodes1.Begin() : nodes0.Begin()),
false);
849 Eval<DIM>(order, coeff, nodes_, value);
850 nodes_[dir1/2].ReInit(nodes.Dim(), nodes.Begin(),
false);
861 for(Integer i = 0; i < Ncoeff; i++) coeff[i * Ncoeff + i] = 1;
862 Grad<DIM>(order, coeff, &coeff_grad);
863 for (Integer i = 0; i < Ncoeff; i++){
864 for (Integer j = 0; j < Ncoeff; j++){
865 M_grad[i + Ncoeff * 0][j + Ncoeff * 0] = coeff_grad[j + (i * DIM + dir0/2) * Ncoeff];
866 M_grad[i + Ncoeff * 1][j + Ncoeff * 1] = coeff_grad[j + (i * DIM + dir1/2) * Ncoeff];
871 auto fn_perturb = [&](std::function<ValueType(ValueType)> fn,
bool even) {
875 Integer N0=pvfmm::pow<Integer>(order, dir0/2);
876 Integer N1=pvfmm::pow<Integer>(order, 1);
877 Integer N2=pvfmm::pow<Integer>(order, DIM - dir0/2 - 1);
878 PVFMM_ASSERT(N0 * N2 == Ngrid);
881 for (Integer i0=0;i0<N0;i0++){
882 for (Integer i2=0;i2<N2;i2++){
883 for (Integer i1=0;i1<N1;i1++){
884 val[(i2*N1+i1)*N0+i0] = (dir0 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1])) * (even ? 1.0 : -1.0);
886 coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 0,
false);
887 Approx<DIM>(order, val, coeff);
888 for (Integer i1=0;i1<N1;i1++){
889 val[(i2*N1+i1)*N0+i0] = 0;
895 Integer N0=pvfmm::pow<Integer>(order, dir1/2);
896 Integer N1=pvfmm::pow<Integer>(order, 1);
897 Integer N2=pvfmm::pow<Integer>(order, DIM - dir1/2 - 1);
898 PVFMM_ASSERT(N0 * N2 == Ngrid);
901 for (Integer i0=0;i0<N0;i0++){
902 for (Integer i2=0;i2<N2;i2++){
903 for (Integer i1=0;i1<N1;i1++){
904 val[(i2*N1+i1)*N0+i0] = (dir1 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1]));
906 coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 1,
false);
907 Approx<DIM>(order, val, coeff);
908 for (Integer i1=0;i1<N1;i1++){
909 val[(i2*N1+i1)*N0+i0] = 0;
919 Mfilter[0].ReInit(2*Ncoeff, 2*Ncoeff);
920 Mfilter[1].ReInit(2*Ncoeff, 2*Ncoeff);
921 Mfilter[0].SetZero();
922 Mfilter[1].SetZero();
923 for (Integer i=0;i<Ncoeff;i++) {
924 Mfilter[0][i + Ncoeff * 0][i + Ncoeff * 0] = 1;
925 Mfilter[1][i + Ncoeff * 1][i + Ncoeff * 1] = 1;
929 if (CONTINUITY == 0) {
930 auto fn0 = [](ValueType x) {
return x;};
932 M[dir0][dir1] = M_diff * M0;
933 }
else if (CONTINUITY == 1) {
934 auto fn0 = [](ValueType x) {
return (-2*x + 3) * x * x;};
935 auto fn1 = [](ValueType x) {
return (1 - x) * x * x;};
938 M[dir0][dir1] = M_diff * M0;
939 if (dir0 & 1) M[dir0][dir1] += (M_grad+M_grad) * (Mfilter[0] * M_diff * M1 * Mfilter[0]);
940 else M[dir0][dir1] -= (M_grad+M_grad) * (Mfilter[0] * M_diff * M1 * Mfilter[0]);
941 if (dir1 & 1) M[dir0][dir1] -= (M_grad+M_grad) * (Mfilter[1] * M_diff * M1 * Mfilter[1]);
942 else M[dir0][dir1] += (M_grad+M_grad) * (Mfilter[1] * M_diff * M1 * Mfilter[1]);
944 if (CONTINUITY == 1) {
945 auto fn1 = [](ValueType x) {
return (1 - x) * x * x;};
947 MM[dir0][dir1] = M_grad * M_diff * M1;
949 for (Integer i=0;i<Ncoeff;i++){
950 for (Integer j=0;j<2*Ncoeff;j++){
951 MM[dir0][dir1][i + Ncoeff*1][j]*=-1;
955 for (Integer i=0;i<2*Ncoeff;i++){
956 for (Integer j=0;j<Ncoeff;j++){
957 MM[dir0][dir1][i][j + Ncoeff*0]*=(dir0 & 1 ? 1.0 : -1.0);
958 MM[dir0][dir1][i][j + Ncoeff*1]*=(dir1 & 1 ? 1.0 : -1.0);
963 for (Integer i=0;i<2*Ncoeff;i++){
964 M[dir0][dir1][i][i]+=1.0;
965 MM[dir0][dir1][i][i]+=1.0;
967 M[dir0][dir1] = Mtrunc * M[dir0][dir1] * Mtrunc;
968 MM[dir0][dir1] = Mtrunc * MM[dir0][dir1] * Mtrunc;
970 for (Integer i=0;i<10;i++) {
971 M[dir0][dir1]=M[dir0][dir1]*M[dir0][dir1];
976 for (Long i = 0; i < dof; i++) {
977 for (Integer j = 0; j < Ncoeff; j++) {
978 x[i][Ncoeff * 0 + j] = coeff0[i * Ncoeff + j];
979 x[i][Ncoeff * 1 + j] = coeff1[i * Ncoeff + j];
985 for (Integer j = 0; j < Ncoeff; j++) {
986 xx[0][Ncoeff * 0 + j] = coeff0[norm0 * Ncoeff + j];
987 xx[0][Ncoeff * 1 + j] = coeff1[norm1 * Ncoeff + j];
990 for (Integer j = 0; j < Ncoeff; j++) {
991 y[norm0][Ncoeff * 0 + j] = yy[0][Ncoeff * 0 + j];
992 y[norm1][Ncoeff * 1 + j] = yy[0][Ncoeff * 1 + j];
995 for (Long i = 0; i < dof; i++) {
996 for (Integer j = 0; j < Ncoeff; j++) {
997 coeff0[i * Ncoeff + j] = y[i][Ncoeff * 0 + j];
998 coeff1[i * Ncoeff + j] = y[i][Ncoeff * 1 + j];
1006 void (*EvalBasis1D)(Integer,
const Vector<ValueType>&, Vector<ValueType>&) = Derived::EvalBasis1D;
1007 void (*Nodes1D)(Integer, Vector<ValueType>&) = Derived::Nodes1D;
1011 if (nodes.Dim() != order) nodes.ReInit(order);
1012 for (Integer i = 0; i < order; i++) {
1013 nodes[i] = -pvfmm::cos<ValueType>((i + (ValueType)0.5) * pvfmm::const_pi<ValueType>() / order) * 0.5 + 0.5;
1018 Integer n = x.Dim();
1019 if (y.Dim() != order * n) y.ReInit(order * n);
1022 for (Long i = 0; i < n; i++) {
1027 for (Long i = 0; i < n; i++) {
1028 y[i + n] = x[i] * 2.0 - 1.0;
1031 for (Integer i = 2; i < order; i++) {
1032 for (Long j = 0; j < n; j++) {
1033 y[i * n + j] = 2 * y[n + j] * y[i * n - 1 * n + j] - y[i * n - 2 * n + j];
1041 PVFMM_ASSERT(order < x_lst.Dim());
1043 if (x.Dim() != order) x.ReInit(order);
1044 if (w.Dim() != order) w.ReInit(order);
1047 #pragma omp critical(QUAD_RULE) 1048 if (x_lst[order].Dim()) {
1051 for (Integer i = 0; i < order; i++) {
1061 if (std::is_same<ValueType, double>::value || std::is_same<ValueType, float>::value) {
1065 double alpha = 0.0, beta = 0.0, a = -1.0, b = 1.0;
1066 cgqf(order, kind, (
double)alpha, (
double)beta, (
double)a, (
double)b, &xd[0], &wd[0]);
1067 for (Integer i = 0; i < order; i++) {
1068 x_[i] = 0.5 * xd[i] + 0.5;
1069 w_[i] = 0.5 * wd[i];
1072 cheb_nodes_1d(order, x_);
1073 for (Integer i = 0; i < order; i++) w_[i] = 0;
1076 cheb_basis_1d(order, x_, V_cheb);
1077 for (
size_t i = 0; i < order; i++) V_cheb[i] /= 2.0;
1082 for (Integer i = 0; i < order; i += 2) w_sample[i] = -((ValueType)2.0 / (i + 1) / (i - 1));
1084 for (Integer i = 0; i < order; i++) {
1085 for (Integer j = 0; j < order; j++) {
1086 w_[j] += M[i][j] * w_sample[i] / order;
1090 #pragma omp critical(QUAD_RULE) 1091 if (!x_lst[order].Dim()) {
1092 x_lst[order].Swap(x_);
1093 w_lst[order].Swap(w_);
1095 quad_rule(order, x, w);
1098 static ValueType machine_eps() {
1099 ValueType eps = 1.0;
1100 while (eps + (ValueType)1.0 > 1.0) eps *= 0.5;
1105 static const ValueType eps = machine_eps() * 64;
1106 ValueType side_inv = 1.0 / side;
1107 if (!Nq) Nq = order;
1110 quad_rule(Nq, qp, qw);
1115 for (Integer i = 0; i < SUBDIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
1117 StaticArray<Integer, 2> kdim;
1118 kdim[0] = ker.Dim(0);
1119 kdim[1] = ker.Dim(1);
1121 StaticArray<Integer, DIM> perm0;
1122 StaticArray<ValueType, DIM> trg;
1124 PVFMM_ASSERT(0 <= src_face && src_face < 2 * DIM);
1125 if (SUBDIM == DIM - 1) {
1126 for (Integer i = 0; i < DIM; i++) {
1127 perm0[i] = (i + (src_face >> 1) + 1) % DIM;
1130 for (Integer i = 0; i < DIM; i++) {
1134 for (Integer i = 0; i < DIM; i++) trg[i] = trg_[perm0[i]];
1135 if (SUBDIM == DIM - 1) trg[DIM - 1] -= side * (src_face & 1);
1142 for (Integer i = 0; i < SUBDIM; i++) {
1143 r_.PushBack(fabs(trg[i] - 0.0));
1144 r_.PushBack(fabs(trg[i] - side));
1146 std::sort(r_.Begin(), r_.Begin() + r_.Dim());
1148 ValueType r0, r1 = r_[r_.Dim() - 1];
1149 r0 = (r1 > side ? r1 - side : 0.0);
1150 for (Integer i = SUBDIM; i < DIM; i++) r0 = std::max(r0, fabs(trg[i]));
1151 if (r0 > eps) r.PushBack(-r0);
1154 for (Integer i = 0; i < r_.Dim(); i++) {
1156 while (r[r.Dim() - 1] > 0.0 && 3.0 * r[r.Dim() - 1] < r_[i]) r.PushBack(3.0 * r[r.Dim() - 1]);
1163 StaticArray<Vector<ValueType>, SUBDIM> eval_mesh;
1164 StaticArray<Vector<ValueType>, SUBDIM> eval_poly;
1173 for (Integer k = 0; k < DIM; k++) r_src[k] = 0.0;
1174 if (SUBDIM == DIM - 1) {
1176 for (Integer k = 0; k < DIM; k++) n_src[k] = 0.0;
1177 n_src[src_face >> 1] = (src_face & 1 ? -1.0 : 1.0);
1179 v_src.ReInit(kdim[0]);
1184 Matrix<ValueType> Mtensor(kdim[1] * kdim[0], pvfmm::pow<Integer>(order, SUBDIM));
1187 for (Integer i0 = 0; i0 < r.Dim() - 1; i0++) {
1188 for (Integer i1 = 0; i1 < 2 * SUBDIM; i1++) {
1189 StaticArray<ValueType, 2 * SUBDIM> range0;
1190 StaticArray<ValueType, 2 * SUBDIM> range1;
1192 for (Integer k = 0; k < SUBDIM; k++) {
1194 ValueType s = (i1 & 1 ? 1.0 : -1.0);
1195 range0[k * 2 + 0] = trg[k] + s * r[i0 + 0];
1196 range0[k * 2 + 1] = trg[k] + s * r[i0 + 0];
1197 range1[k * 2 + 0] = trg[k] + s * r[i0 + 1];
1198 range1[k * 2 + 1] = trg[k] + s * r[i0 + 1];
1200 range0[k * 2 + 0] = trg[k] - fabs(r[i0 + 0]);
1201 range0[k * 2 + 1] = trg[k] + fabs(r[i0 + 0]);
1202 range1[k * 2 + 0] = trg[k] - fabs(r[i0 + 1]);
1203 range1[k * 2 + 1] = trg[k] + fabs(r[i0 + 1]);
1206 for (Integer k = 0; k < 2 * SUBDIM; k++) {
1207 if (range0[k] > side) range0[k] = side;
1208 if (range0[k] < 0.0) range0[k] = 0.0;
1209 if (range1[k] > side) range1[k] = side;
1210 if (range1[k] < 0.0) range1[k] = 0.0;
1213 bool continue_flag =
false;
1214 for (Integer k = 0; k < SUBDIM; k++) {
1216 if (fabs(range0[2 * k + 0] - range1[2 * k + 0]) < eps && fabs(range0[2 * k + 1] - range1[2 * k + 1]) < eps) {
1217 continue_flag =
true;
1221 if (fabs(range0[2 * k + 0] - range0[2 * k + 1]) < eps && fabs(range1[2 * k + 0] - range1[2 * k + 1]) < eps) {
1222 continue_flag =
true;
1227 if (continue_flag)
continue;
1229 for (Integer i2 = 0; i2 < Nq; i2++) {
1230 StaticArray<ValueType, 2 * SUBDIM> range;
1231 for (Integer k = 0; k < 2 * SUBDIM; k++) {
1232 range[k] = range0[k] + (range1[k] - range0[k]) * qp[i2];
1234 for (Integer k = 0; k < SUBDIM; k++) {
1235 if (k == (i1 >> 1)) {
1236 eval_mesh[k].ReInit(1);
1237 eval_mesh[k][0] = range[2 * k];
1239 eval_mesh[k].ReInit(Nq);
1240 for (Integer l = 0; l < Nq; l++) eval_mesh[k][l] = range[2 * k + 0] + (range[2 * k + 1] - range[2 * k + 0]) * qp[l];
1245 eval_coord.ReInit(0);
1246 for (Integer k = 0; k < SUBDIM; k++) {
1247 Integer Nk = eval_mesh[k].Dim();
1248 eval_coord_tmp.Swap(eval_coord);
1249 eval_coord.ReInit(Nk * N * DIM);
1250 for (Integer l0 = 0; l0 < Nk; l0++) {
1251 for (Integer l1 = 0; l1 < N; l1++) {
1252 for (Integer l2 = 0; l2 < k; l2++) {
1253 eval_coord[DIM * (N * l0 + l1) + l2] = eval_coord_tmp[DIM * l1 + l2];
1255 eval_coord[DIM * (N * l0 + l1) + k] = trg[k] - eval_mesh[k][l0];
1260 StaticArray<ValueType, DIM> c;
1261 for (Integer k = 0; k < N; k++) {
1262 for (Integer l = 0; l < SUBDIM; l++) c[l] = eval_coord[k * DIM + l];
1263 for (Integer l = SUBDIM; l < DIM; l++) c[l] = trg[l];
1264 for (Integer l = 0; l < DIM; l++) eval_coord[k * DIM + perm0[l]] = c[l];
1267 for (Integer k = 0; k < SUBDIM; k++) {
1268 Integer N = eval_mesh[k].Dim();
1269 for (Integer l = 0; l < eval_mesh[k].Dim(); l++) {
1270 eval_mesh[k][l] *= side_inv;
1272 Derived::EvalBasis1D(order, eval_mesh[k], eval_poly[k]);
1273 if (k == (i1 >> 1)) {
1275 ValueType qscal = fabs(range1[i1] - range0[i1]);
1276 for (Integer l0 = 0; l0 < order; l0++) {
1277 eval_poly[k][l0] *= qscal * qw[i2];
1281 ValueType qscal = (range[2 * k + 1] - range[2 * k + 0]);
1282 for (Integer l0 = 0; l0 < order; l0++) {
1283 for (Integer l1 = 0; l1 < N; l1++) {
1284 eval_poly[k][N * l0 + l1] *= qscal * qw[l1];
1290 Integer N = eval_coord.Dim() / DIM;
1291 kern_value.ReInit(kdim[0] * N * kdim[1]);
1292 kern_value.SetZero();
1293 for (Integer j = 0; j < kdim[0]; j++) {
1294 for (Integer k = 0; k < kdim[0]; k++) v_src[k] = 0.0;
1296 Vector<ValueType> ker_value(N * kdim[1], kern_value.Begin() + j * N * kdim[1],
false);
1297 ker(r_src, n_src, v_src, eval_coord, ker_value);
1300 v0.ReInit(kern_value.Dim());
1301 for (Integer k = 0; k < v0.Dim(); k++) v0[k] = kern_value[k];
1304 for (Integer l0 = 0; l0 < M1.Dim(0); l0++) {
1305 for (Integer l1 = 0; l1 < M1.Dim(1); l1++) {
1306 M1[l0][l1] = M0[l1][l0];
1312 Matrix<ValueType> Mkern(eval_mesh[SUBDIM - 1].Dim(), kern_value.Dim() / eval_mesh[SUBDIM - 1].Dim(), kern_value.Begin(),
false);
1313 for (Integer k = SUBDIM - 1; k >= 0; k--) {
1314 Matrix<ValueType> Mpoly(order, eval_mesh[k].Dim(), eval_poly[k].Begin(),
false);
1316 v1.ReInit(Mpoly.Dim(0) * Mkern.Dim(1));
1320 v0.ReInit(v1.Dim());
1322 for (Integer l0 = 0; l0 < Mt.Dim(0); l0++) {
1323 for (Integer l1 = 0; l1 < Mt.Dim(1); l1++) {
1324 Mt[l0][l1] = Mcoef[l1][l0];
1329 Mkern.ReInit(eval_mesh[k - 1].Dim(), v0.Dim() / eval_mesh[k - 1].Dim(), v0.Begin(),
false);
1333 assert(v0.Dim() == Mtensor.Dim(0) * Mtensor.Dim(1));
1334 for (Integer k = 0; k < v0.Dim(); k++) {
1335 Mtensor[0][k] += v0[k];
1339 if (r[i0] < 0.0)
break;
1343 Mtensor = Mtensor.Transpose();
1345 if (Mcoeff.Dim(0) != kdim[1] || Mcoeff.Dim(1) != kdim[0] * Ncoeff) {
1346 Mcoeff.ReInit(kdim[1], kdim[0] * Ncoeff);
1348 Vector<ValueType> Mtensor_(Mtensor.Dim(0) * Mtensor.Dim(1), Mtensor.Begin(),
false);
1349 Vector<ValueType> Mcoeff_(Mcoeff.Dim(0) * Mcoeff.Dim(1), Mcoeff.Begin(),
false);
1350 tensor2coeff<SUBDIM>(order, Mtensor_, Mcoeff_);
1356 Nodes<1>(order, nodes);
1357 Integer N = nodes.Dim();
1360 for (Integer i = 0; i < N; i++) {
1361 for (Integer j = 0; j < N; j++) {
1363 for (Integer l = 0; l < N; l++) {
1366 for (Integer k = 0; k < N; k++) {
1369 Mij *= 1 / (nodes[i] - nodes[k]);
1371 Mij *= (nodes[j] - nodes[k]) / (nodes[i] - nodes[k]);
1382 Derived::EvalBasis1D(order, nodes, p);
1387 Approx<1>(order,
Vector<ValueType>(M0.Dim(0) * M0.Dim(1), M0.Begin(),
false), coeff);
1388 (*M) =
Matrix<ValueType>(M0.Dim(0), coeff.Dim() / M0.Dim(0), coeff.Begin(),
false);
1413 #endif //_PVFMM_CHEB_UTILS_HPP_ Definition: cheb_utils.hpp:14
Definition: cheb_utils.hpp:12
Definition: cheb_utils.hpp:1394
Definition: matrix.hpp:15
static ValueType TruncErr(Integer order, const Vector< ValueType > &coeff)
Returns the sum of the absolute value of coefficients of the highest order terms as an estimate of tr...
Definition: cheb_utils.hpp:216
Definition: matrix.hpp:12
static void Eval(Integer order, const Vector< ValueType > &coeff, ConstIterator< Vector< ValueType >> in_x, Vector< ValueType > &out)
Evaluates values from input coefficients at points on a regular grid defined by in_x, in_y, in_z the values in the input vector.
Definition: cheb_utils.hpp:157
static void Approx(Integer order, const Vector< ValueType > &fn_v, Vector< ValueType > &coeff)
Computes approximation from function values at node points.
Definition: cheb_utils.hpp:50
static void EvalBasis1D(Integer order, const Vector< ValueType > &x, Vector< ValueType > &y)
Returns the values of all Chebyshev polynomials up to degree d, evaluated at points in the input vect...
Definition: cheb_utils.hpp:1406
static void Grad(Integer order, const Vector< ValueType > &coeff_in, Vector< ValueType > *coeff_out)
Compute gradient.
Definition: cheb_utils.hpp:260
Definition: kernel.hpp:14