cheb_utils.hpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408
  1. #ifndef _SCTL_CHEB_UTILS_HPP_
  2. #define _SCTL_CHEB_UTILS_HPP_
  3. #include <sctl/common.hpp>
  4. #include SCTL_INCLUDE(matrix.hpp)
  5. #include SCTL_INCLUDE(math_utils.hpp)
  6. #include SCTL_INCLUDE(legendre_rule.hpp)
  7. #include <type_traits>
  8. #include <functional>
  9. #include <algorithm>
  10. namespace SCTL_NAMESPACE {
  11. template <class ValueType, class Derived> class BasisInterface {
  12. public:
  13. template <Integer DIM> static void Nodes(Integer order, Vector<ValueType>& nodes) {
  14. if (DIM == 1) {
  15. Derived::Nodes1D(order, nodes);
  16. return;
  17. }
  18. Vector<ValueType> nodes1d;
  19. Derived::Nodes1D(order, nodes1d);
  20. Integer order_DIM = pow<Integer>(order, DIM);
  21. if (nodes.Dim() != order_DIM * DIM) nodes.ReInit(order_DIM * DIM);
  22. StaticArray<Integer, DIM> idx;
  23. for (Integer i = 0; i < DIM; i++) idx[i] = 0;
  24. Integer itr = 0;
  25. for (Integer j = 0; j < order_DIM; j++) {
  26. for (Integer i = 0; i < DIM; i++) {
  27. if (idx[i] == order) idx[i] = 0;
  28. nodes[itr + i] = nodes1d[idx[i]];
  29. }
  30. itr += DIM;
  31. idx[0]++;
  32. for (Integer i = 1; i < DIM; i++) {
  33. if (idx[i - 1] == order) idx[i]++;
  34. }
  35. }
  36. }
  37. /**
  38. * \brief Computes approximation from function values at node points.
  39. * \param[in] fn_v Function values at node points (dof x order^DIM).
  40. * \param[out] coeff Coefficient values (dof x Ncoeff).
  41. */
  42. template <Integer DIM> static void Approx(Integer order, const Vector<ValueType>& fn_v, Vector<ValueType>& coeff) {
  43. Matrix<ValueType> Mp;
  44. { // Precompute
  45. static Vector<Matrix<ValueType>> precomp(1000);
  46. SCTL_ASSERT(order < precomp.Dim());
  47. if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
  48. #pragma omp critical(SCTL_BASIS_APPROX)
  49. if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
  50. Vector<ValueType> x, p;
  51. Derived::Nodes1D(order, x);
  52. Derived::EvalBasis1D(order, x, p);
  53. Matrix<ValueType> Mp1(order, order, p.begin(), false);
  54. Mp1.pinv().Swap(precomp[order]);
  55. }
  56. }
  57. Mp.ReInit(precomp[order].Dim(0), precomp[order].Dim(1), precomp[order].begin(), false);
  58. }
  59. Integer order_DIM = pow<Integer>(order, DIM);
  60. Integer order_DIM_ = pow<Integer>(order, DIM - 1);
  61. Long dof = fn_v.Dim() / order_DIM;
  62. SCTL_ASSERT(fn_v.Dim() == dof * order_DIM);
  63. // Create work buffers
  64. Long buff_size = dof * order_DIM;
  65. Vector<ValueType> buff(2 * buff_size);
  66. Iterator<ValueType> buff1 = buff.begin() + buff_size * 0;
  67. Iterator<ValueType> buff2 = buff.begin() + buff_size * 1;
  68. Vector<ValueType> fn(order_DIM * dof, (Iterator<ValueType>)fn_v.begin(), false);
  69. for (Integer k = 0; k < DIM; k++) { // Apply Mp along k-dimension
  70. Matrix<ValueType> Mi(dof * order_DIM_, order, fn.begin(), false);
  71. Matrix<ValueType> Mo(dof * order_DIM_, order, buff2, false);
  72. Matrix<ValueType>::GEMM(Mo, Mi, Mp);
  73. Matrix<ValueType> Mo_t(order, dof * order_DIM_, buff1, false);
  74. for (Long i = 0; i < Mo.Dim(0); i++) {
  75. for (Long j = 0; j < Mo.Dim(1); j++) {
  76. Mo_t[j][i] = Mo[i][j];
  77. }
  78. }
  79. fn.ReInit(order_DIM * dof, buff1, false);
  80. }
  81. { // Rearrange and write to coeff
  82. Vector<ValueType> tensor(order_DIM * dof, buff1, false);
  83. tensor2coeff<DIM>(order, tensor, coeff);
  84. }
  85. }
  86. template <Integer DIM> static void Approx_(Integer order, const Vector<ValueType>& fn_v, Vector<ValueType>& coeff, ValueType scale) {
  87. Matrix<ValueType> Mp;
  88. { // Precompute
  89. static Vector<Matrix<ValueType>> precomp(1000);
  90. SCTL_ASSERT(order < precomp.Dim());
  91. if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
  92. #pragma omp critical(SCTL_BASIS_APPROX)
  93. if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
  94. Vector<ValueType> x, p;
  95. Derived::Nodes1D(order, x);
  96. for (Integer i = 0; i < order; i++) x[i] = (x[i] - 0.5) * scale + 0.5;
  97. Derived::EvalBasis1D(order, x, p);
  98. Matrix<ValueType> Mp1(order, order, p.begin(), false);
  99. Mp1.pinv().Swap(precomp[order]);
  100. }
  101. }
  102. Mp.ReInit(precomp[order].Dim(0), precomp[order].Dim(1), precomp[order].begin(), false);
  103. }
  104. Integer order_DIM = pow<Integer>(order, DIM);
  105. Integer order_DIM_ = pow<Integer>(order, DIM - 1);
  106. Long dof = fn_v.Dim() / order_DIM;
  107. SCTL_ASSERT(fn_v.Dim() == dof * order_DIM);
  108. // Create work buffers
  109. Long buff_size = dof * order_DIM;
  110. Vector<ValueType> buff(2 * buff_size);
  111. Iterator<ValueType> buff1 = buff.begin() + buff_size * 0;
  112. Iterator<ValueType> buff2 = buff.begin() + buff_size * 1;
  113. Vector<ValueType> fn(order_DIM * dof, (Iterator<ValueType>)fn_v.begin(), false);
  114. for (Integer k = 0; k < DIM; k++) { // Apply Mp along k-dimension
  115. Matrix<ValueType> Mi(dof * order_DIM_, order, fn.begin(), false);
  116. Matrix<ValueType> Mo(dof * order_DIM_, order, buff2, false);
  117. Matrix<ValueType>::GEMM(Mo, Mi, Mp);
  118. Matrix<ValueType> Mo_t(order, dof * order_DIM_, buff1, false);
  119. for (Long i = 0; i < Mo.Dim(0); i++) {
  120. for (Long j = 0; j < Mo.Dim(1); j++) {
  121. Mo_t[j][i] = Mo[i][j];
  122. }
  123. }
  124. fn.ReInit(order_DIM * dof, buff1, false);
  125. }
  126. { // Rearrange and write to coeff
  127. Vector<ValueType> tensor(order_DIM * dof, buff1, false);
  128. tensor2coeff<DIM>(order, tensor, coeff);
  129. }
  130. }
  131. /**
  132. * \brief Evaluates values from input coefficients at points on a regular
  133. * grid defined by in_x, in_y, in_z the values in the input vector.
  134. * \param[in] coeff Coefficient values (dof x Ncoeff).
  135. * \param[out] out Values at node points (in_x[DIM-1].Dim() x ... x in_x[0].Dim() x dof).
  136. */
  137. template <Integer DIM> static void Eval(Integer order, const Vector<ValueType>& coeff, ConstIterator<Vector<ValueType>> in_x, Vector<ValueType>& out) {
  138. Integer Ncoeff = 1;
  139. for (Integer i = 0; i < DIM; i++) {
  140. Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  141. }
  142. Long dof = coeff.Dim() / Ncoeff;
  143. SCTL_ASSERT(coeff.Dim() == Ncoeff * dof);
  144. // Precomputation
  145. Long buff_size = dof;
  146. StaticArray<Matrix<ValueType>, DIM> Mp;
  147. for (Integer i = 0; i < DIM; i++) {
  148. Integer n = in_x[i].Dim();
  149. if (!n) return;
  150. Mp[i].ReInit(order, n);
  151. Vector<ValueType> p(order * n, Mp[i].begin(), false);
  152. Derived::EvalBasis1D(order, in_x[i], p);
  153. buff_size *= std::max(order, n);
  154. }
  155. // Create work buffers
  156. Vector<ValueType> buff(2 * buff_size);
  157. Iterator<ValueType> buff1 = buff.begin() + buff_size * 0;
  158. Iterator<ValueType> buff2 = buff.begin() + buff_size * 1;
  159. { // Rearrange coefficients into a tensor.
  160. Vector<ValueType> tensor(dof * pow<Integer>(order, DIM), buff1, false);
  161. coeff2tensor<DIM>(order, coeff, tensor);
  162. }
  163. { // ReInit out
  164. Long len = dof;
  165. for (Integer i = 0; i < DIM; i++) len *= in_x[i].Dim();
  166. if (out.Dim() != len) out.ReInit(len);
  167. }
  168. for (Integer k = 0; k < DIM; k++) { // Apply Mp along k-dimension
  169. Integer order_DIM = pow<Integer>(order, DIM - k - 1);
  170. for (Integer i = 0; i < k; i++) order_DIM *= in_x[i].Dim();
  171. Matrix<ValueType> Mi(dof * order_DIM, order, buff1, false);
  172. Matrix<ValueType> Mo(dof * order_DIM, in_x[k].Dim(), buff2, false);
  173. Matrix<ValueType>::GEMM(Mo, Mi, Mp[k]);
  174. Matrix<ValueType> Mo_t(in_x[k].Dim(), dof * order_DIM, buff1, false);
  175. if (k == DIM - 1) Mo_t.ReInit(in_x[k].Dim(), dof * order_DIM, out.begin(), false);
  176. for (Long i = 0; i < Mo.Dim(0); i++) {
  177. for (Long j = 0; j < Mo.Dim(1); j++) {
  178. Mo_t[j][i] = Mo[i][j];
  179. }
  180. }
  181. }
  182. }
  183. /**
  184. * \brief Returns the sum of the absolute value of coefficients of the
  185. * highest order terms as an estimate of truncation error.
  186. * \param[in] coeff Coefficient values (dof x Ncoeff).
  187. */
  188. template <Integer DIM> static ValueType TruncErr(Integer order, const Vector<ValueType>& coeff) {
  189. Integer Ncoeff = 1;
  190. { // Set Ncoeff
  191. for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  192. }
  193. Long dof = coeff.Dim() / Ncoeff;
  194. SCTL_ASSERT(coeff.Dim() == Ncoeff * dof);
  195. ValueType err = 0;
  196. for (Long l = 0; l < dof; l++) { // TODO: optimize this
  197. Long offset0 = l * Ncoeff;
  198. Integer indx0 = 0;
  199. Integer indx1 = 0;
  200. StaticArray<Integer, DIM + 1> i0;
  201. for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
  202. Integer sum = 0;
  203. while (1) {
  204. if (sum < order) {
  205. if (sum == order - 1) err += fabs<ValueType>(coeff[offset0 + indx0]);
  206. indx0++;
  207. }
  208. indx1++;
  209. sum++;
  210. i0[0]++;
  211. for (Integer j = 0; j < DIM && i0[j] == order; j++) {
  212. i0[j] = 0;
  213. i0[j + 1]++;
  214. sum = sum + 1 - order;
  215. }
  216. if (i0[DIM]) break;
  217. }
  218. }
  219. return err;
  220. }
  221. /**
  222. * \brief Compute gradient.
  223. * \param[in] coeff_in Input coefficients (dof x Ncoeff)
  224. * \param[out] coeff_out Output coefficients (dof x DIM x Ncoeff)
  225. */
  226. template <Integer DIM> static void Grad(Integer order, const Vector<ValueType>& coeff_in, Vector<ValueType>* coeff_out) {
  227. Integer Ncoeff = 1;
  228. for (Integer i = 0; i < DIM; i++) {
  229. Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  230. }
  231. Long dof = coeff_in.Dim() / Ncoeff;
  232. SCTL_ASSERT(coeff_in.Dim() == Ncoeff * dof);
  233. Matrix<ValueType> Mdiff;
  234. { // Precompute
  235. static Vector<Matrix<ValueType>> precomp(1000);
  236. SCTL_ASSERT(order < precomp.Dim());
  237. if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
  238. #pragma omp critical(SCTL_BASIS_GRAD)
  239. if (precomp[order].Dim(0) * precomp[order].Dim(1) == 0) {
  240. Matrix<ValueType> M;
  241. diff_1d(order, &M);
  242. M.Swap(precomp[order]);
  243. }
  244. }
  245. Mdiff.ReInit(precomp[order].Dim(0), precomp[order].Dim(1), precomp[order].begin(), false);
  246. }
  247. // Create work buffers
  248. Long buff_size = dof * pow<Integer>(order, DIM);
  249. Vector<ValueType> buff((3 + DIM) * buff_size);
  250. Vector<ValueType> buff0(buff_size * 1, buff.begin() + buff_size * 0, false);
  251. Vector<ValueType> buff1(buff_size * 1, buff.begin() + buff_size * 1, false);
  252. Vector<ValueType> buff2(buff_size * 1, buff.begin() + buff_size * 2, false);
  253. Vector<ValueType> buff3(buff_size * DIM, buff.begin() + buff_size * 3, false);
  254. { // buff0 <-- coeff2tensor(coeff_in);
  255. coeff2tensor<DIM>(order, coeff_in, buff0);
  256. }
  257. for (Integer k = 0; k < DIM; k++) { // buff2 <-- Grad(buff0)
  258. Long N0 = pow<Integer>(order, k);
  259. Long N1 = order;
  260. Long N2 = pow<Integer>(order, DIM - k - 1);
  261. for (Long i3 = 0; i3 < dof; i3++) { // buff1 <-- transpose(buff0)
  262. for (Long i2 = 0; i2 < N2; i2++) {
  263. for (Long i1 = 0; i1 < N1; i1++) {
  264. for (Long i0 = 0; i0 < N0; i0++) {
  265. buff1[((i3 * N2 + i2) * N0 + i0) * N1 + i1] = buff0[((i3 * N2 + i2) * N1 + i1) * N0 + i0];
  266. }
  267. }
  268. }
  269. }
  270. { // buff2 <-- buff1 * Mdiff
  271. Matrix<ValueType> Mi(dof * N0 * N2, N1, buff1.begin(), false);
  272. Matrix<ValueType> Mo(dof * N0 * N2, N1, buff2.begin(), false);
  273. Matrix<ValueType>::GEMM(Mo, Mi, Mdiff);
  274. }
  275. for (Long i3 = 0; i3 < dof; i3++) { // buff3 <-- transpose(buff2)
  276. for (Long i2 = 0; i2 < N2; i2++) {
  277. for (Long i1 = 0; i1 < N1; i1++) {
  278. for (Long i0 = 0; i0 < N0; i0++) {
  279. buff3[(((i2 * N1 + i1) * N0 + i0) * dof + i3) * DIM + k] = buff2[((i3 * N2 + i2) * N0 + i0) * N1 + i1];
  280. }
  281. }
  282. }
  283. }
  284. }
  285. { // coeff_out <-- tensor2coeff(buff2);
  286. tensor2coeff<DIM>(order, buff3, *coeff_out);
  287. }
  288. }
  289. template <Integer DIM, Integer SUBDIM, class Kernel> static void Integ(Matrix<ValueType>& Mcoeff, Integer order, ConstIterator<ValueType> trg_, ValueType side, Integer src_face, const Kernel& ker, ValueType tol = -1, Integer Nq = 0) {
  290. if (!Nq) Nq = order;
  291. Integ_<DIM, SUBDIM>(Mcoeff, order, trg_, side, src_face, ker, Nq);
  292. if (tol < 0) tol = machine_eps<ValueType>() * 256;
  293. ValueType err = tol + 1;
  294. Matrix<ValueType> Mtmp;
  295. while (err > tol) {
  296. err = 0;
  297. ValueType max_val = pow<SUBDIM>(side);
  298. Nq = std::max((Integer)(Nq * 1.26), Nq + 1);
  299. Integ_<DIM, SUBDIM>(Mtmp, order, trg_, side, src_face, ker, Nq);
  300. for (Integer i = 0; i < Mtmp.Dim(0) * Mtmp.Dim(1); i++) {
  301. err = std::max(err, fabs<ValueType>(Mtmp[0][i] - Mcoeff[0][i]));
  302. max_val = std::max(max_val, fabs<ValueType>(Mtmp[0][i]));
  303. }
  304. err /= max_val;
  305. Mcoeff = Mtmp;
  306. if (Nq>200) {
  307. SCTL_WARN("Failed to converge, error = "<<err);
  308. break;
  309. }
  310. }
  311. Mcoeff = Mcoeff.Transpose();
  312. }
  313. template <Integer DIM> static void tensor2coeff(Integer order, const Vector<ValueType>& tensor, Vector<ValueType>& coeff) {
  314. Integer Ncoeff = 1, Ntensor = pow<Integer>(order, DIM);
  315. for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  316. Long dof = tensor.Dim() / Ntensor;
  317. SCTL_ASSERT(tensor.Dim() == Ntensor * dof);
  318. if (coeff.Dim() != Ncoeff * dof) coeff.ReInit(Ncoeff * dof);
  319. for (Long l = 0; l < dof; l++) { // TODO: optimize this
  320. Long offset0 = l * Ncoeff;
  321. Integer indx0 = 0;
  322. Integer indx1 = 0;
  323. StaticArray<Integer, DIM + 1> i0;
  324. for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
  325. Integer sum = 0;
  326. while (1) {
  327. if (sum < order) {
  328. coeff[offset0 + indx0] = tensor[l + indx1 * dof];
  329. indx0++;
  330. }
  331. indx1++;
  332. sum++;
  333. i0[0]++;
  334. for (Integer j = 0; j < DIM && i0[j] == order; j++) {
  335. i0[j] = 0;
  336. i0[j + 1]++;
  337. sum = sum + 1 - order;
  338. }
  339. if (i0[DIM]) break;
  340. }
  341. }
  342. }
  343. template <Integer DIM> static void coeff2tensor(Integer order, const Vector<ValueType>& coeff, Vector<ValueType>& tensor) {
  344. Integer Ncoeff = 1, Ntensor = pow<Integer>(order, DIM);
  345. for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  346. Long dof = coeff.Dim() / Ncoeff;
  347. SCTL_ASSERT(coeff.Dim() == Ncoeff * dof);
  348. if (tensor.Dim() != Ntensor * dof) tensor.ReInit(Ntensor * dof);
  349. for (Long l = 0; l < dof; l++) { // TODO: optimize this
  350. Long offset0 = l * Ncoeff;
  351. Long offset1 = l * Ntensor;
  352. Integer indx0 = 0;
  353. Integer indx1 = 0;
  354. StaticArray<Integer, DIM + 1> i0;
  355. for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
  356. Integer sum = 0;
  357. while (1) {
  358. if (sum < order) {
  359. tensor[offset1 + indx1] = coeff[offset0 + indx0];
  360. indx0++;
  361. } else {
  362. tensor[offset1 + indx1] = 0;
  363. }
  364. indx1++;
  365. sum++;
  366. i0[0]++;
  367. for (Integer j = 0; j < DIM && i0[j] == order; j++) {
  368. i0[j] = 0;
  369. i0[j + 1]++;
  370. sum = sum + 1 - order;
  371. }
  372. if (i0[DIM]) break;
  373. }
  374. }
  375. }
  376. template <Integer DIM> static void Truncate(Vector<ValueType> &coeff0, Integer order0, Integer order1) {
  377. SCTL_ASSERT(order1 <= order0);
  378. Integer Ncoeff0 = 1, Ncoeff1 = 1;
  379. for (Integer i = 0; i < DIM; i++) Ncoeff0 = (Ncoeff0 * (order0 + i)) / (i + 1);
  380. for (Integer i = 0; i < DIM; i++) Ncoeff1 = (Ncoeff1 * (order1 + i)) / (i + 1);
  381. Long dof = coeff0.Dim() / Ncoeff0;
  382. SCTL_ASSERT(coeff0.Dim() == Ncoeff0 * dof);
  383. Vector<ValueType> coeff1(dof * Ncoeff1);
  384. coeff1.SetZero();
  385. for (Long l = 0; l < dof; l++) { // TODO: optimize this
  386. Long offset0 = l * Ncoeff0;
  387. Long offset1 = l * Ncoeff1;
  388. Integer indx0 = 0;
  389. Integer indx1 = 0;
  390. StaticArray<Integer, DIM + 1> i0;
  391. for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
  392. Integer sum = 0;
  393. while (1) {
  394. if (sum < order1) coeff1[offset1 + indx1] = coeff0[offset0 + indx0];
  395. if (sum < order0) indx0++;
  396. if (sum < order1) indx1++;
  397. sum++;
  398. i0[0]++;
  399. for (Integer j = 0; j < DIM && i0[j] == order0; j++) {
  400. i0[j] = 0;
  401. i0[j + 1]++;
  402. sum = sum + 1 - order0;
  403. }
  404. if (i0[DIM]) break;
  405. }
  406. }
  407. coeff0 = coeff1;
  408. }
  409. template <Integer DIM> static void Reflect(Vector<ValueType> &coeff, Integer order, Integer dir) {
  410. SCTL_ASSERT(dir < DIM);
  411. Integer Ncoeff = 1;
  412. for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  413. Long dof = coeff.Dim() / Ncoeff;
  414. SCTL_ASSERT(coeff.Dim() == Ncoeff * dof);
  415. for (Long l = 0; l < dof; l++) { // TODO: optimize this
  416. Long offset = l * Ncoeff;
  417. Integer indx = 0;
  418. StaticArray<Integer, DIM + 1> i0;
  419. for (Integer i = 0; i <= DIM; i++) i0[i] = 0;
  420. Integer sum = 0;
  421. while (1) {
  422. if (sum < order) coeff[offset + indx] = coeff[offset + indx] * (i0[dir] % 2 ? -1 : 1) * (1);
  423. if (sum < order) indx++;
  424. sum++;
  425. i0[0]++;
  426. for (Integer j = 0; j < DIM && i0[j] == order; j++) {
  427. i0[j] = 0;
  428. i0[j + 1]++;
  429. sum = sum + 1 - order;
  430. }
  431. if (i0[DIM]) break;
  432. }
  433. }
  434. }
  435. template <Integer DIM, Integer CONTINUITY> static void MakeContinuous(Vector<ValueType> &coeff0, Vector<ValueType> &coeff1, Integer order, Integer dir0, Integer dir1) {
  436. if (dir0>=2*DIM || dir1>=2*DIM) return;
  437. Integer Ncoeff = 1;
  438. for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  439. Long dof = coeff0.Dim() / Ncoeff;
  440. SCTL_ASSERT(coeff0.Dim() == Ncoeff * dof);
  441. SCTL_ASSERT(coeff1.Dim() == Ncoeff * dof);
  442. static Matrix<Matrix<ValueType>> M(2*DIM, 2*DIM);
  443. if (M[dir0][dir1].Dim(0) != 2 * Ncoeff) {
  444. Integer Ngrid = pow<Integer>(order, DIM - 1);
  445. Vector<ValueType> nodes;
  446. Nodes<1>(order, nodes);
  447. Matrix<ValueType> M_diff(2*Ncoeff, Ngrid);
  448. { // Set M_diff
  449. M_diff.SetZero();
  450. StaticArray<Vector<ValueType>, DIM> nodes_;
  451. for (Integer i = 0; i < DIM; i++) { // Set nodes_
  452. nodes_[i].ReInit(nodes.Dim(), nodes.begin(), false);
  453. }
  454. Vector<ValueType> nodes0, nodes1;
  455. nodes0.PushBack(0);
  456. nodes1.PushBack(1);
  457. Vector<ValueType> value;
  458. Vector<ValueType> coeff(Ncoeff);
  459. coeff.SetZero();
  460. for (Integer i = 0; i < Ncoeff; i++) {
  461. coeff[i]=0.5;
  462. value.ReInit(Ngrid, M_diff[i + Ncoeff * 0], false);
  463. nodes_[dir0/2].ReInit(1, (dir0 & 1 ? nodes1.begin() : nodes0.begin()), false);
  464. Eval<DIM>(order, coeff, nodes_, value);
  465. nodes_[dir0/2].ReInit(nodes.Dim(), nodes.begin(), false);
  466. coeff[i]=-0.5;
  467. value.ReInit(Ngrid, M_diff[i + Ncoeff * 1], false);
  468. nodes_[dir1/2].ReInit(1, (dir1 & 1 ? nodes1.begin() : nodes0.begin()), false);
  469. Eval<DIM>(order, coeff, nodes_, value);
  470. nodes_[dir1/2].ReInit(nodes.Dim(), nodes.begin(), false);
  471. coeff[i]=0;
  472. }
  473. }
  474. Matrix<ValueType> M_grad(2 * Ncoeff, 2 * Ncoeff);
  475. { // Set M_grad
  476. M_grad.SetZero();
  477. Vector<ValueType> coeff(Ncoeff * Ncoeff), coeff_grad;
  478. coeff.SetZero();
  479. for(Integer i = 0; i < Ncoeff; i++) coeff[i * Ncoeff + i] = 1;
  480. Grad<DIM>(order, coeff, &coeff_grad);
  481. for (Integer i = 0; i < Ncoeff; i++){
  482. for (Integer j = 0; j < Ncoeff; j++){
  483. M_grad[i + Ncoeff * 0][j + Ncoeff * 0] = coeff_grad[j + (i * DIM + dir0/2) * Ncoeff];
  484. M_grad[i + Ncoeff * 1][j + Ncoeff * 1] = coeff_grad[j + (i * DIM + dir1/2) * Ncoeff];
  485. }
  486. }
  487. }
  488. auto fn_perturb = [&](std::function<ValueType(ValueType)> fn, bool even) { // Set M0
  489. Matrix<ValueType> M0(Ngrid, 2 * Ncoeff);
  490. M0.SetZero();
  491. { // dir0
  492. Integer N0=pow<Integer>(order, dir0/2);
  493. Integer N1=pow<Integer>(order, 1);
  494. Integer N2=pow<Integer>(order, DIM - dir0/2 - 1);
  495. SCTL_ASSERT(N0 * N2 == Ngrid);
  496. Vector<ValueType> val(Ngrid * order), coeff;
  497. val.SetZero();
  498. for (Integer i0=0;i0<N0;i0++){
  499. for (Integer i2=0;i2<N2;i2++){
  500. for (Integer i1=0;i1<N1;i1++){
  501. val[(i2*N1+i1)*N0+i0] = (dir0 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1])) * (even ? 1.0 : -1.0);
  502. }
  503. coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 0, false);
  504. Approx<DIM>(order, val, coeff);
  505. for (Integer i1=0;i1<N1;i1++){
  506. val[(i2*N1+i1)*N0+i0] = 0;
  507. }
  508. }
  509. }
  510. }
  511. { // dir1
  512. Integer N0=pow<Integer>(order, dir1/2);
  513. Integer N1=pow<Integer>(order, 1);
  514. Integer N2=pow<Integer>(order, DIM - dir1/2 - 1);
  515. SCTL_ASSERT(N0 * N2 == Ngrid);
  516. Vector<ValueType> val(Ngrid * order), coeff;
  517. val.SetZero();
  518. for (Integer i0=0;i0<N0;i0++){
  519. for (Integer i2=0;i2<N2;i2++){
  520. for (Integer i1=0;i1<N1;i1++){
  521. val[(i2*N1+i1)*N0+i0] = (dir1 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1]));
  522. }
  523. coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 1, false);
  524. Approx<DIM>(order, val, coeff);
  525. for (Integer i1=0;i1<N1;i1++){
  526. val[(i2*N1+i1)*N0+i0] = 0;
  527. }
  528. }
  529. }
  530. }
  531. return M0;
  532. };
  533. if (CONTINUITY == 0) {
  534. auto fn0 = [](ValueType x) {return x;};
  535. Matrix<ValueType> M0 = fn_perturb(fn0, 0);
  536. M[dir0][dir1] = M_diff * M0;
  537. } else if (CONTINUITY == 1) {
  538. auto fn0 = [](ValueType x) {return (-2*x + 3) * x * x;};
  539. auto fn1 = [](ValueType x) {return (1 - x) * x * x;};
  540. Matrix<ValueType> M0 = fn_perturb(fn0, 0);
  541. Matrix<ValueType> M1 = fn_perturb(fn1, 1);
  542. M[dir0][dir1] = M_diff * M0 + M_grad * M_diff * M1;
  543. } else if (CONTINUITY == 2) {
  544. auto fn0 = [](ValueType x) {return x*x*x*(6*x*x-15*x+10);};
  545. auto fn1 = [](ValueType x) {return x*x*x*(-3*x*x+7*x-4);};
  546. auto fn2 = [](ValueType x) {return x*x*x*(0.5*x*x-1*x+0.5);};
  547. Matrix<ValueType> M0 = fn_perturb(fn0, 0);
  548. Matrix<ValueType> M1 = fn_perturb(fn1, 1);
  549. Matrix<ValueType> M2 = fn_perturb(fn2, 0);
  550. M[dir0][dir1] = M_diff * M0 + M_grad * M_diff * M1 + M_grad * M_grad * M_diff * M2;
  551. }
  552. for (Integer i=0;i<2*Ncoeff;i++){
  553. M[dir0][dir1][i][i]+=1.0;
  554. }
  555. if(0){ //// Alternate approach // DOESN'T WORK
  556. //Matrix<ValueType> Mgrid2coeff;
  557. //{ // Set Mgrid2coeff
  558. // Integer Ngrid = pow<Integer>(order, DIM);
  559. // Matrix<ValueType> M(Ngrid, Ncoeff);
  560. // Vector<ValueType> val(Ngrid);
  561. // val.SetZero();
  562. // for (Integer i=0;i<Ngrid;i++) {
  563. // val[i]=1.0;
  564. // Vector<ValueType> coeff(Ncoeff, M[i], false);
  565. // Approx<DIM>(order, val, coeff);
  566. // val[i]=0.0;
  567. // }
  568. // Mgrid2coeff.ReInit(2*Ngrid, 2*Ncoeff);
  569. // Mgrid2coeff.SetZero();
  570. // for(Integer i=0;i<Ngrid;i++){
  571. // for(Integer j=0;j<Ncoeff;j++){
  572. // Mgrid2coeff[i+Ngrid*0][j+Ncoeff*0]=M[i][j];
  573. // Mgrid2coeff[i+Ngrid*1][j+Ncoeff*1]=M[i][j];
  574. // }
  575. // }
  576. //}
  577. //Matrix<ValueType> Mcoeff2grid;
  578. //{ // Set Mgrid2coeff
  579. // StaticArray<Vector<ValueType>, DIM> nodes_;
  580. // for (Integer i = 0; i < DIM; i++) { // Set nodes_
  581. // nodes_[i].ReInit(nodes.Dim(), nodes.begin(), false);
  582. // }
  583. // Integer Ngrid = pow<Integer>(order, DIM);
  584. // Matrix<ValueType> M(Ncoeff, Ngrid);
  585. // Vector<ValueType> coeff(Ncoeff);
  586. // coeff.SetZero();
  587. // for (Integer i=0;i<Ncoeff;i++) {
  588. // coeff[i]=1.0;
  589. // Vector<ValueType> val(Ngrid, M[i], false);
  590. // Eval<DIM>(order, coeff, nodes_, val);
  591. // coeff[i]=0.0;
  592. // }
  593. // Mcoeff2grid.ReInit(2*Ncoeff, 2*Ngrid);
  594. // Mcoeff2grid.SetZero();
  595. // for(Integer i=0;i<Ncoeff;i++){
  596. // for(Integer j=0;j<Ngrid;j++){
  597. // Mcoeff2grid[i+Ncoeff*0][j+Ngrid*0]=M[i][j];
  598. // Mcoeff2grid[i+Ncoeff*1][j+Ngrid*1]=M[i][j];
  599. // }
  600. // }
  601. //}
  602. //if(0){
  603. // Integer Ngrid0 = Ngrid*order;
  604. // Matrix<ValueType> MM(2*Ngrid0 + 2*Ngrid, 2*Ngrid0);
  605. // MM.SetZero();
  606. // for (Integer i=0;i<2*Ngrid0;i++) MM[i][i]=1;
  607. // Matrix<ValueType> M0_(Ngrid, 2 * Ngrid0, MM[2 * Ngrid0 + Ngrid * 0], false); M0_ = (Mgrid2coeff * M_diff).Transpose();
  608. // Matrix<ValueType> M1_(Ngrid, 2 * Ngrid0, MM[2 * Ngrid0 + Ngrid * 1], false); M1_ = (Mgrid2coeff * M_grad * M_diff).Transpose();
  609. // for (Long i=0;i<2*Ngrid*2*Ngrid0;i++) MM[0][2*Ngrid0*2*Ngrid0 +i] *= 10000;
  610. // MM = MM.Transpose().pinv();
  611. // M[dir].ReInit(2 * Ngrid0, 2 * Ngrid0, MM.begin());
  612. // M[dir] = Mcoeff2grid * M[dir] * Mgrid2coeff;
  613. //} else {
  614. // SCTL_ASSERT(DIM==2);
  615. // Vector<ValueType> coeff_weight;
  616. // for (Integer i=0;i<order;i++) {
  617. // for (Integer j=0;j<order;j++) {
  618. // if(i+j<order) coeff_weight.PushBack(pow<ValueType>(1.5, i+j)*1e-4);
  619. // }
  620. // }
  621. // SCTL_ASSERT(coeff_weight.Dim()==Ncoeff);
  622. // auto M0_ = M_diff.Transpose();
  623. // auto M1_ = (M_grad * M_diff).Transpose();
  624. // Matrix<ValueType> MM(2*Ncoeff + 6*Ngrid, 2*Ncoeff);
  625. // MM.SetZero();
  626. // for (Integer i=0;i<Ncoeff;i++) {
  627. // MM[i+Ncoeff*0][i+Ncoeff*0]=coeff_weight[i];
  628. // MM[i+Ncoeff*1][i+Ncoeff*1]=coeff_weight[i];
  629. // }
  630. // for (Integer i=0;i<Ngrid;i++) {
  631. // for (Integer j=0;j<Ncoeff;j++) {
  632. // MM[2 * Ncoeff + 0 * Ngrid +i][0 * Ncoeff + j] = M0_[0 * Ngrid + i][0 * Ncoeff + j];
  633. // MM[2 * Ncoeff + 0 * Ngrid +i][1 * Ncoeff + j] = M0_[0 * Ngrid + i][1 * Ncoeff + j];
  634. // MM[2 * Ncoeff + 1 * Ngrid +i][0 * Ncoeff + j] = M1_[0 * Ngrid + i][0 * Ncoeff + j];
  635. // MM[2 * Ncoeff + 1 * Ngrid +i][1 * Ncoeff + j] = M1_[0 * Ngrid + i][1 * Ncoeff + j];
  636. // MM[2 * Ncoeff + 2 * Ngrid +i][0 * Ncoeff + j] = M0_[0 * Ngrid + i][1 * Ncoeff + j];
  637. // MM[2 * Ncoeff + 3 * Ngrid +i][1 * Ncoeff + j] = M0_[0 * Ngrid + i][0 * Ncoeff + j];
  638. // MM[2 * Ncoeff + 4 * Ngrid +i][0 * Ncoeff + j] = M1_[0 * Ngrid + i][1 * Ncoeff + j];
  639. // MM[2 * Ncoeff + 5 * Ngrid +i][1 * Ncoeff + j] = M1_[0 * Ngrid + i][0 * Ncoeff + j];
  640. // }
  641. // }
  642. // Matrix<ValueType> MMM(2*Ncoeff + 6*Ngrid, 2*Ncoeff);
  643. // MMM.SetZero();
  644. // for (Integer i=0;i<Ncoeff;i++) {
  645. // MMM[i+Ncoeff*0][i+Ncoeff*0]=coeff_weight[i];
  646. // MMM[i+Ncoeff*1][i+Ncoeff*1]=coeff_weight[i];
  647. // }
  648. // for (Integer i=0;i<Ngrid;i++) {
  649. // for (Integer j=0;j<Ncoeff;j++) {
  650. // // MMM[2 * Ncoeff + 0 * Ngrid +i][0 * Ncoeff + j] = M0_[0 * Ngrid + i][0 * Ncoeff + j];
  651. // // MMM[2 * Ncoeff + 0 * Ngrid +i][1 * Ncoeff + j] = M0_[0 * Ngrid + i][1 * Ncoeff + j];
  652. // // MMM[2 * Ncoeff + 1 * Ngrid +i][0 * Ncoeff + j] = M1_[0 * Ngrid + i][0 * Ncoeff + j];
  653. // // MMM[2 * Ncoeff + 1 * Ngrid +i][1 * Ncoeff + j] = M1_[0 * Ngrid + i][1 * Ncoeff + j];
  654. // MMM[2 * Ncoeff + 2 * Ngrid +i][0 * Ncoeff + j] = M0_[0 * Ngrid + i][1 * Ncoeff + j];
  655. // MMM[2 * Ncoeff + 3 * Ngrid +i][1 * Ncoeff + j] = M0_[0 * Ngrid + i][0 * Ncoeff + j];
  656. // MMM[2 * Ncoeff + 4 * Ngrid +i][0 * Ncoeff + j] = M1_[0 * Ngrid + i][1 * Ncoeff + j];
  657. // MMM[2 * Ncoeff + 5 * Ngrid +i][1 * Ncoeff + j] = M1_[0 * Ngrid + i][0 * Ncoeff + j];
  658. // }
  659. // }
  660. // M[dir] = (MM.pinv(1e-10) * MMM).Transpose();
  661. //}
  662. //M[dir]=M[dir]*M[dir];
  663. ////M[dir]=M[dir]*M[dir];
  664. ////M[dir]=M[dir]*M[dir];
  665. ////M[dir]=M[dir]*M[dir];
  666. ////M[dir]=M[dir]*M[dir];
  667. ////M[dir]=M[dir]*M[dir];
  668. ////M[dir]=M[dir]*M[dir];
  669. ////M[dir]=M[dir]*M[dir];
  670. ////M[dir]=M[dir]*M[dir];
  671. ////M[dir]=M[dir]*M[dir];
  672. ////M[dir]=M[dir]*M[dir];
  673. ////M[dir]=M[dir]*M[dir];
  674. ////M[dir]=M[dir]*M[dir];
  675. ////M[dir]=M[dir]*M[dir];
  676. ////M[dir]=M[dir]*M[dir];
  677. ////M[dir]=M[dir]*M[dir];
  678. }
  679. }
  680. Matrix<ValueType> x(dof, 2 * Ncoeff), y(dof, 2 * Ncoeff);
  681. for (Long i = 0; i < dof; i++) {
  682. for (Integer j = 0; j < Ncoeff; j++) {
  683. x[i][Ncoeff * 0 + j] = coeff0[i * Ncoeff + j];
  684. x[i][Ncoeff * 1 + j] = coeff1[i * Ncoeff + j];
  685. }
  686. }
  687. Matrix<ValueType>::GEMM(y, x, M[dir0][dir1]);
  688. for (Long i = 0; i < dof; i++) {
  689. for (Integer j = 0; j < Ncoeff; j++) {
  690. coeff0[i * Ncoeff + j] = y[i][Ncoeff * 0 + j];
  691. coeff1[i * Ncoeff + j] = y[i][Ncoeff * 1 + j];
  692. }
  693. }
  694. }
  695. template <Integer DIM, Integer CONTINUITY> static void MakeContinuousEdge(Vector<ValueType> &coeff0, Vector<ValueType> &coeff1, Integer order, Integer dir0, Integer dir1, Integer norm0, Integer norm1) {
  696. SCTL_ASSERT(DIM==2);
  697. if (dir0>=2*DIM || dir1>=2*DIM) return;
  698. Integer Ncoeff = 1;
  699. for (Integer i = 0; i < DIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  700. Long dof = coeff0.Dim() / Ncoeff;
  701. SCTL_ASSERT(coeff0.Dim() == Ncoeff * dof);
  702. SCTL_ASSERT(coeff1.Dim() == Ncoeff * dof);
  703. static Matrix<Matrix<ValueType>> M(2*DIM, 2*DIM);
  704. static Matrix<Matrix<ValueType>> MM(2*DIM, 2*DIM);
  705. if (M[dir0][dir1].Dim(0) != 2 * Ncoeff) {
  706. Integer Ngrid = pow<Integer>(order, DIM - 1);
  707. Vector<ValueType> nodes;
  708. Nodes<1>(order, nodes);
  709. Matrix<ValueType> Mtrunc(2*Ncoeff, 2*Ncoeff);
  710. { // Set Mtrunc
  711. Vector<ValueType> w;
  712. w.SetZero();
  713. for (Integer i=0;i<order;i++){
  714. for (Integer j=0;j<order;j++){
  715. if (i+j<order) {
  716. w.PushBack(i<order-CONTINUITY*2-1 && j<order-CONTINUITY*2-1);
  717. }
  718. }
  719. }
  720. Mtrunc.SetZero();
  721. for (Integer i=0;i<Ncoeff;i++){
  722. Mtrunc[i + Ncoeff * 0][i + Ncoeff * 0] = w[i];
  723. Mtrunc[i + Ncoeff * 1][i + Ncoeff * 1] = w[i];
  724. }
  725. }
  726. Matrix<ValueType> M_diff(2*Ncoeff, Ngrid);
  727. { // Set M_diff
  728. M_diff.SetZero();
  729. StaticArray<Vector<ValueType>, DIM> nodes_;
  730. for (Integer i = 0; i < DIM; i++) { // Set nodes_
  731. nodes_[i].ReInit(nodes.Dim(), nodes.begin(), false);
  732. }
  733. Vector<ValueType> nodes0, nodes1;
  734. nodes0.PushBack(0);
  735. nodes1.PushBack(1);
  736. Vector<ValueType> value;
  737. Vector<ValueType> coeff(Ncoeff);
  738. coeff.SetZero();
  739. for (Integer i = 0; i < Ncoeff; i++) {
  740. coeff[i]=0.5;
  741. value.ReInit(Ngrid, M_diff[i + Ncoeff * 0], false);
  742. nodes_[dir0/2].ReInit(1, (dir0 & 1 ? nodes1.begin() : nodes0.begin()), false);
  743. Eval<DIM>(order, coeff, nodes_, value);
  744. nodes_[dir0/2].ReInit(nodes.Dim(), nodes.begin(), false);
  745. coeff[i]=-0.5;
  746. value.ReInit(Ngrid, M_diff[i + Ncoeff * 1], false);
  747. nodes_[dir1/2].ReInit(1, (dir1 & 1 ? nodes1.begin() : nodes0.begin()), false);
  748. Eval<DIM>(order, coeff, nodes_, value);
  749. nodes_[dir1/2].ReInit(nodes.Dim(), nodes.begin(), false);
  750. coeff[i]=0;
  751. }
  752. }
  753. Matrix<ValueType> M_grad(2 * Ncoeff, 2 * Ncoeff);
  754. { // Set M_grad
  755. M_grad.SetZero();
  756. Vector<ValueType> coeff(Ncoeff * Ncoeff), coeff_grad;
  757. coeff.SetZero();
  758. for(Integer i = 0; i < Ncoeff; i++) coeff[i * Ncoeff + i] = 1;
  759. Grad<DIM>(order, coeff, &coeff_grad);
  760. for (Integer i = 0; i < Ncoeff; i++){
  761. for (Integer j = 0; j < Ncoeff; j++){
  762. M_grad[i + Ncoeff * 0][j + Ncoeff * 0] = coeff_grad[j + (i * DIM + dir0/2) * Ncoeff];
  763. M_grad[i + Ncoeff * 1][j + Ncoeff * 1] = coeff_grad[j + (i * DIM + dir1/2) * Ncoeff];
  764. }
  765. }
  766. }
  767. auto fn_perturb = [&](std::function<ValueType(ValueType)> fn, bool even) { // Set M0
  768. Matrix<ValueType> M0(Ngrid, 2 * Ncoeff);
  769. M0.SetZero();
  770. { // dir0
  771. Integer N0=pow<Integer>(order, dir0/2);
  772. Integer N1=pow<Integer>(order, 1);
  773. Integer N2=pow<Integer>(order, DIM - dir0/2 - 1);
  774. SCTL_ASSERT(N0 * N2 == Ngrid);
  775. Vector<ValueType> val(Ngrid * order), coeff;
  776. val.SetZero();
  777. for (Integer i0=0;i0<N0;i0++){
  778. for (Integer i2=0;i2<N2;i2++){
  779. for (Integer i1=0;i1<N1;i1++){
  780. val[(i2*N1+i1)*N0+i0] = (dir0 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1])) * (even ? 1.0 : -1.0);
  781. }
  782. coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 0, false);
  783. Approx<DIM>(order, val, coeff);
  784. for (Integer i1=0;i1<N1;i1++){
  785. val[(i2*N1+i1)*N0+i0] = 0;
  786. }
  787. }
  788. }
  789. }
  790. { // dir1
  791. Integer N0=pow<Integer>(order, dir1/2);
  792. Integer N1=pow<Integer>(order, 1);
  793. Integer N2=pow<Integer>(order, DIM - dir1/2 - 1);
  794. SCTL_ASSERT(N0 * N2 == Ngrid);
  795. Vector<ValueType> val(Ngrid * order), coeff;
  796. val.SetZero();
  797. for (Integer i0=0;i0<N0;i0++){
  798. for (Integer i2=0;i2<N2;i2++){
  799. for (Integer i1=0;i1<N1;i1++){
  800. val[(i2*N1+i1)*N0+i0] = (dir1 & 1 ? fn(nodes[i1]) : fn(1.0 - nodes[i1]));
  801. }
  802. coeff.ReInit(Ncoeff, M0[i2 * N0 + i0] + Ncoeff * 1, false);
  803. Approx<DIM>(order, val, coeff);
  804. for (Integer i1=0;i1<N1;i1++){
  805. val[(i2*N1+i1)*N0+i0] = 0;
  806. }
  807. }
  808. }
  809. }
  810. return M0;
  811. };
  812. Matrix<ValueType> Mfilter[2];
  813. { // Set Mfilter
  814. Mfilter[0].ReInit(2*Ncoeff, 2*Ncoeff);
  815. Mfilter[1].ReInit(2*Ncoeff, 2*Ncoeff);
  816. Mfilter[0].SetZero();
  817. Mfilter[1].SetZero();
  818. for (Integer i=0;i<Ncoeff;i++) {
  819. Mfilter[0][i + Ncoeff * 0][i + Ncoeff * 0] = 1;
  820. Mfilter[1][i + Ncoeff * 1][i + Ncoeff * 1] = 1;
  821. }
  822. }
  823. if (CONTINUITY == 0) {
  824. auto fn0 = [](ValueType x) {return x;};
  825. Matrix<ValueType> M0 = fn_perturb(fn0, 0);
  826. M[dir0][dir1] = M_diff * M0;
  827. } else if (CONTINUITY == 1) {
  828. auto fn0 = [](ValueType x) {return (-2*x + 3) * x * x;};
  829. auto fn1 = [](ValueType x) {return (1 - x) * x * x;};
  830. Matrix<ValueType> M0 = fn_perturb(fn0, 0);
  831. Matrix<ValueType> M1 = fn_perturb(fn1, 1);
  832. M[dir0][dir1] = M_diff * M0;
  833. if (dir0 & 1) M[dir0][dir1] += (M_grad+M_grad) * (Mfilter[0] * M_diff * M1 * Mfilter[0]);
  834. else M[dir0][dir1] -= (M_grad+M_grad) * (Mfilter[0] * M_diff * M1 * Mfilter[0]);
  835. if (dir1 & 1) M[dir0][dir1] -= (M_grad+M_grad) * (Mfilter[1] * M_diff * M1 * Mfilter[1]);
  836. else M[dir0][dir1] += (M_grad+M_grad) * (Mfilter[1] * M_diff * M1 * Mfilter[1]);
  837. }
  838. if (CONTINUITY == 1) {
  839. auto fn1 = [](ValueType x) {return (1 - x) * x * x;};
  840. Matrix<ValueType> M1 = fn_perturb(fn1, 1);
  841. MM[dir0][dir1] = M_grad * M_diff * M1;
  842. for (Integer i=0;i<Ncoeff;i++){
  843. for (Integer j=0;j<2*Ncoeff;j++){
  844. MM[dir0][dir1][i + Ncoeff*1][j]*=-1;
  845. }
  846. }
  847. for (Integer i=0;i<2*Ncoeff;i++){
  848. for (Integer j=0;j<Ncoeff;j++){
  849. MM[dir0][dir1][i][j + Ncoeff*0]*=(dir0 & 1 ? 1.0 : -1.0);
  850. MM[dir0][dir1][i][j + Ncoeff*1]*=(dir1 & 1 ? 1.0 : -1.0);
  851. }
  852. }
  853. }
  854. for (Integer i=0;i<2*Ncoeff;i++){
  855. M[dir0][dir1][i][i]+=1.0;
  856. MM[dir0][dir1][i][i]+=1.0;
  857. }
  858. M[dir0][dir1] = Mtrunc * M[dir0][dir1] * Mtrunc;
  859. MM[dir0][dir1] = Mtrunc * MM[dir0][dir1] * Mtrunc;
  860. for (Integer i=0;i<10;i++) {
  861. M[dir0][dir1]=M[dir0][dir1]*M[dir0][dir1];
  862. }
  863. }
  864. Matrix<ValueType> x(dof, 2 * Ncoeff), y(dof, 2 * Ncoeff);
  865. for (Long i = 0; i < dof; i++) {
  866. for (Integer j = 0; j < Ncoeff; j++) {
  867. x[i][Ncoeff * 0 + j] = coeff0[i * Ncoeff + j];
  868. x[i][Ncoeff * 1 + j] = coeff1[i * Ncoeff + j];
  869. }
  870. }
  871. Matrix<ValueType>::GEMM(y, x, M[dir0][dir1]);
  872. { ////
  873. Matrix<ValueType> xx(1, 2*Ncoeff), yy(1, 2*Ncoeff);
  874. for (Integer j = 0; j < Ncoeff; j++) {
  875. xx[0][Ncoeff * 0 + j] = coeff0[norm0 * Ncoeff + j];
  876. xx[0][Ncoeff * 1 + j] = coeff1[norm1 * Ncoeff + j];
  877. }
  878. Matrix<ValueType>::GEMM(yy, xx, MM[dir0][dir1]);
  879. for (Integer j = 0; j < Ncoeff; j++) {
  880. y[norm0][Ncoeff * 0 + j] = yy[0][Ncoeff * 0 + j];
  881. y[norm1][Ncoeff * 1 + j] = yy[0][Ncoeff * 1 + j];
  882. }
  883. }
  884. for (Long i = 0; i < dof; i++) {
  885. for (Integer j = 0; j < Ncoeff; j++) {
  886. coeff0[i * Ncoeff + j] = y[i][Ncoeff * 0 + j];
  887. coeff1[i * Ncoeff + j] = y[i][Ncoeff * 1 + j];
  888. }
  889. }
  890. }
  891. static void quad_rule(Integer order, Vector<ValueType>& x, Vector<ValueType>& w) {
  892. static Vector<Vector<ValueType>> x_lst(10000);
  893. static Vector<Vector<ValueType>> w_lst(x_lst.Dim());
  894. SCTL_ASSERT(order < x_lst.Dim());
  895. if (x.Dim() != order) x.ReInit(order);
  896. if (w.Dim() != order) w.ReInit(order);
  897. if (!order) return;
  898. bool done = false;
  899. #pragma omp critical(SCTL_QUAD_RULE)
  900. if (x_lst[order].Dim()) {
  901. Vector<ValueType>& x_ = x_lst[order];
  902. Vector<ValueType>& w_ = w_lst[order];
  903. for (Integer i = 0; i < order; i++) {
  904. x[i] = x_[i];
  905. w[i] = w_[i];
  906. }
  907. done = true;
  908. }
  909. if (done) return;
  910. Vector<ValueType> x_(order);
  911. Vector<ValueType> w_(order);
  912. if (std::is_same<ValueType, double>::value || std::is_same<ValueType, float>::value) { // Gauss-Legendre quadrature nodes and weights
  913. Vector<double> xd(order);
  914. Vector<double> wd(order);
  915. int kind = 1;
  916. double alpha = 0.0, beta = 0.0, a = -1.0, b = 1.0;
  917. cgqf(order, kind, (double)alpha, (double)beta, (double)a, (double)b, &xd[0], &wd[0]);
  918. for (Integer i = 0; i < order; i++) {
  919. x_[i] = (ValueType)(0.5 * xd[i] + 0.5);
  920. w_[i] = (ValueType)(0.5 * wd[i]);
  921. }
  922. } else { // Chebyshev quadrature nodes and weights
  923. cheb_nodes_1d(order, x_);
  924. for (Integer i = 0; i < order; i++) w_[i] = 0;
  925. Vector<ValueType> V_cheb(order * order);
  926. cheb_basis_1d(order, x_, V_cheb);
  927. for (Integer i = 0; i < order; i++) V_cheb[i] /= 2.0;
  928. Matrix<ValueType> M(order, order, V_cheb.begin());
  929. Vector<ValueType> w_sample(order);
  930. w_sample.SetZero();
  931. for (Integer i = 0; i < order; i += 2) w_sample[i] = -((ValueType)2.0 / (i + 1) / (i - 1));
  932. for (Integer i = 0; i < order; i++) {
  933. for (Integer j = 0; j < order; j++) {
  934. w_[j] += M[i][j] * w_sample[i] / order;
  935. }
  936. }
  937. }
  938. #pragma omp critical(SCTL_QUAD_RULE)
  939. if (!x_lst[order].Dim()) { // Set x_lst, w_lst
  940. x_lst[order].Swap(x_);
  941. w_lst[order].Swap(w_);
  942. }
  943. quad_rule(order, x, w);
  944. }
  945. private:
  946. BasisInterface() {
  947. void (*EvalBasis1D)(Integer, const Vector<ValueType>&, Vector<ValueType>&) = Derived::EvalBasis1D;
  948. void (*Nodes1D)(Integer, Vector<ValueType>&) = Derived::Nodes1D;
  949. }
  950. static void cheb_nodes_1d(Integer order, Vector<ValueType>& nodes) {
  951. if (nodes.Dim() != order) nodes.ReInit(order);
  952. for (Integer i = 0; i < order; i++) {
  953. nodes[i] = -cos<ValueType>((i + (ValueType)0.5) * const_pi<ValueType>() / order) * (ValueType)0.5 + (ValueType)0.5;
  954. }
  955. }
  956. static void cheb_basis_1d(Integer order, const Vector<ValueType>& x, Vector<ValueType>& y) {
  957. Integer n = x.Dim();
  958. if (y.Dim() != order * n) y.ReInit(order * n);
  959. if (order > 0) {
  960. for (Long i = 0; i < n; i++) {
  961. y[i] = 1.0;
  962. }
  963. }
  964. if (order > 1) {
  965. for (Long i = 0; i < n; i++) {
  966. y[i + n] = x[i] * 2 - 1;
  967. }
  968. }
  969. for (Integer i = 2; i < order; i++) {
  970. for (Long j = 0; j < n; j++) {
  971. y[i * n + j] = 2 * y[n + j] * y[i * n - 1 * n + j] - y[i * n - 2 * n + j];
  972. }
  973. }
  974. }
  975. template <Integer DIM, Integer SUBDIM, class Kernel> static void Integ_(Matrix<ValueType>& Mcoeff, Integer order, ConstIterator<ValueType> trg_, ValueType side, Integer src_face, const Kernel& ker, Integer Nq = 0) {
  976. constexpr ValueType eps = machine_eps<ValueType>() * 64;
  977. ValueType side_inv = 1.0 / side;
  978. if (!Nq) Nq = order;
  979. Vector<ValueType> qp, qw;
  980. quad_rule(Nq, qp, qw);
  981. Integer Ncoeff;
  982. { // Set Ncoeff
  983. Ncoeff = 1;
  984. for (Integer i = 0; i < SUBDIM; i++) Ncoeff = (Ncoeff * (order + i)) / (i + 1);
  985. }
  986. StaticArray<Integer, 2> kdim;
  987. kdim[0] = ker.Dim(0);
  988. kdim[1] = ker.Dim(1);
  989. StaticArray<Integer, DIM> perm0;
  990. StaticArray<ValueType, DIM> trg; // target after rotation
  991. { // Set perm0
  992. SCTL_ASSERT(0 <= src_face && src_face < 2 * DIM);
  993. if (SUBDIM == DIM - 1) {
  994. for (Integer i = 0; i < DIM; i++) {
  995. perm0[i] = (i + (src_face >> 1) + 1) % DIM;
  996. }
  997. } else {
  998. for (Integer i = 0; i < DIM; i++) {
  999. perm0[i] = i;
  1000. }
  1001. }
  1002. for (Integer i = 0; i < DIM; i++) trg[i] = trg_[perm0[i]];
  1003. if (SUBDIM == DIM - 1) trg[DIM - 1] -= side * (src_face & 1);
  1004. }
  1005. Vector<ValueType> r;
  1006. { // Set r
  1007. Vector<ValueType> r_;
  1008. r_.PushBack(0);
  1009. for (Integer i = 0; i < SUBDIM; i++) {
  1010. r_.PushBack(fabs(trg[i] - 0.0));
  1011. r_.PushBack(fabs(trg[i] - side));
  1012. }
  1013. std::sort(r_.begin(), r_.begin() + r_.Dim());
  1014. ValueType r0, r1 = r_[r_.Dim() - 1];
  1015. r0 = (r1 > side ? r1 - side : 0.0);
  1016. for (Integer i = SUBDIM; i < DIM; i++) r0 = std::max(r0, fabs(trg[i]));
  1017. if (r0 > eps) r.PushBack(-r0);
  1018. r.PushBack(r0);
  1019. for (Integer i = 0; i < r_.Dim(); i++) {
  1020. if (r_[i] > r0) {
  1021. while (r[r.Dim() - 1] > 0.0 && 3.0 * r[r.Dim() - 1] < r_[i]) r.PushBack(3.0 * r[r.Dim() - 1]);
  1022. r.PushBack(r_[i]);
  1023. }
  1024. }
  1025. }
  1026. // Work vectors
  1027. StaticArray<Vector<ValueType>, SUBDIM> eval_mesh;
  1028. StaticArray<Vector<ValueType>, SUBDIM> eval_poly;
  1029. Vector<ValueType> eval_coord_tmp;
  1030. Vector<ValueType> eval_coord;
  1031. Vector<ValueType> kern_value;
  1032. // Temporary vectors
  1033. Vector<ValueType> r_src, n_src, v_src;
  1034. { // Init r_src, n_src, v_src
  1035. r_src.ReInit(DIM);
  1036. for (Integer k = 0; k < DIM; k++) r_src[k] = 0.0;
  1037. if (SUBDIM == DIM - 1) {
  1038. n_src.ReInit(DIM);
  1039. for (Integer k = 0; k < DIM; k++) n_src[k] = 0.0;
  1040. n_src[src_face >> 1] = (src_face & 1 ? -1.0 : 1.0);
  1041. }
  1042. v_src.ReInit(kdim[0]);
  1043. }
  1044. Vector<ValueType> v0;
  1045. Vector<ValueType> v1;
  1046. Matrix<ValueType> Mtensor(kdim[1] * kdim[0], pow<Integer>(order, SUBDIM));
  1047. Mtensor.SetZero();
  1048. for (Integer i0 = 0; i0 < r.Dim() - 1; i0++) { // for each layer
  1049. for (Integer i1 = 0; i1 < 2 * SUBDIM; i1++) { // for each direction
  1050. StaticArray<ValueType, 2 * SUBDIM> range0;
  1051. StaticArray<ValueType, 2 * SUBDIM> range1;
  1052. { // Set range0, range1
  1053. for (Integer k = 0; k < SUBDIM; k++) {
  1054. if (i1 >> 1 == k) {
  1055. ValueType s = (i1 & 1 ? 1.0 : -1.0);
  1056. range0[k * 2 + 0] = trg[k] + s * r[i0 + 0];
  1057. range0[k * 2 + 1] = trg[k] + s * r[i0 + 0];
  1058. range1[k * 2 + 0] = trg[k] + s * r[i0 + 1];
  1059. range1[k * 2 + 1] = trg[k] + s * r[i0 + 1];
  1060. } else {
  1061. range0[k * 2 + 0] = trg[k] - fabs(r[i0 + 0]);
  1062. range0[k * 2 + 1] = trg[k] + fabs(r[i0 + 0]);
  1063. range1[k * 2 + 0] = trg[k] - fabs(r[i0 + 1]);
  1064. range1[k * 2 + 1] = trg[k] + fabs(r[i0 + 1]);
  1065. }
  1066. }
  1067. for (Integer k = 0; k < 2 * SUBDIM; k++) {
  1068. if (range0[k] > side) range0[k] = side;
  1069. if (range0[k] < 0.0) range0[k] = 0.0;
  1070. if (range1[k] > side) range1[k] = side;
  1071. if (range1[k] < 0.0) range1[k] = 0.0;
  1072. }
  1073. bool continue_flag = false;
  1074. for (Integer k = 0; k < SUBDIM; k++) { // continue if volume if 0
  1075. if (i1 >> 1 == k) {
  1076. if (fabs(range0[2 * k + 0] - range1[2 * k + 0]) < eps && fabs(range0[2 * k + 1] - range1[2 * k + 1]) < eps) {
  1077. continue_flag = true;
  1078. break;
  1079. }
  1080. } else {
  1081. if (fabs(range0[2 * k + 0] - range0[2 * k + 1]) < eps && fabs(range1[2 * k + 0] - range1[2 * k + 1]) < eps) {
  1082. continue_flag = true;
  1083. break;
  1084. }
  1085. }
  1086. }
  1087. if (continue_flag) continue;
  1088. }
  1089. for (Integer i2 = 0; i2 < Nq; i2++) { // for each quadrature point
  1090. StaticArray<ValueType, 2 * SUBDIM> range;
  1091. for (Integer k = 0; k < 2 * SUBDIM; k++) { // Set range
  1092. range[k] = range0[k] + (range1[k] - range0[k]) * qp[i2];
  1093. }
  1094. for (Integer k = 0; k < SUBDIM; k++) { // Set eval_mesh
  1095. if (k == (i1 >> 1)) {
  1096. eval_mesh[k].ReInit(1);
  1097. eval_mesh[k][0] = range[2 * k];
  1098. } else {
  1099. eval_mesh[k].ReInit(Nq);
  1100. 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];
  1101. }
  1102. }
  1103. { // Set eval_coord
  1104. Integer N = 1;
  1105. eval_coord.ReInit(0);
  1106. for (Integer k = 0; k < SUBDIM; k++) {
  1107. Integer Nk = eval_mesh[k].Dim();
  1108. eval_coord_tmp.Swap(eval_coord);
  1109. eval_coord.ReInit(Nk * N * DIM);
  1110. for (Integer l0 = 0; l0 < Nk; l0++) {
  1111. for (Integer l1 = 0; l1 < N; l1++) {
  1112. for (Integer l2 = 0; l2 < k; l2++) {
  1113. eval_coord[DIM * (N * l0 + l1) + l2] = eval_coord_tmp[DIM * l1 + l2];
  1114. }
  1115. eval_coord[DIM * (N * l0 + l1) + k] = trg[k] - eval_mesh[k][l0];
  1116. }
  1117. }
  1118. N *= Nk;
  1119. }
  1120. StaticArray<ValueType, DIM> c;
  1121. for (Integer k = 0; k < N; k++) { // Rotate
  1122. for (Integer l = 0; l < SUBDIM; l++) c[l] = eval_coord[k * DIM + l];
  1123. for (Integer l = SUBDIM; l < DIM; l++) c[l] = trg[l];
  1124. for (Integer l = 0; l < DIM; l++) eval_coord[k * DIM + perm0[l]] = c[l];
  1125. }
  1126. }
  1127. for (Integer k = 0; k < SUBDIM; k++) { // Set eval_poly
  1128. Integer N = eval_mesh[k].Dim();
  1129. for (Integer l = 0; l < eval_mesh[k].Dim(); l++) { // Scale eval_mesh to [0, 1]
  1130. eval_mesh[k][l] *= side_inv;
  1131. }
  1132. Derived::EvalBasis1D(order, eval_mesh[k], eval_poly[k]);
  1133. if (k == (i1 >> 1)) {
  1134. assert(N == 1);
  1135. ValueType qscal = fabs(range1[i1] - range0[i1]);
  1136. for (Integer l0 = 0; l0 < order; l0++) {
  1137. eval_poly[k][l0] *= qscal * qw[i2];
  1138. }
  1139. } else {
  1140. assert(N == Nq);
  1141. ValueType qscal = (range[2 * k + 1] - range[2 * k + 0]);
  1142. for (Integer l0 = 0; l0 < order; l0++) {
  1143. for (Integer l1 = 0; l1 < N; l1++) {
  1144. eval_poly[k][N * l0 + l1] *= qscal * qw[l1];
  1145. }
  1146. }
  1147. }
  1148. }
  1149. { // Set kern_value
  1150. Integer N = eval_coord.Dim() / DIM;
  1151. kern_value.ReInit(kdim[0] * N * kdim[1]);
  1152. kern_value.SetZero();
  1153. for (Integer j = 0; j < kdim[0]; j++) { // Evaluate ker
  1154. for (Integer k = 0; k < kdim[0]; k++) v_src[k] = 0.0;
  1155. v_src[j] = 1.0;
  1156. Vector<ValueType> ker_value(N * kdim[1], kern_value.begin() + j * N * kdim[1], false);
  1157. ker(r_src, n_src, v_src, eval_coord, ker_value);
  1158. }
  1159. { // Transpose
  1160. v0.ReInit(kern_value.Dim());
  1161. for (Integer k = 0; k < v0.Dim(); k++) v0[k] = kern_value[k];
  1162. Matrix<ValueType> M0(kdim[0], N * kdim[1], v0.begin(), false);
  1163. Matrix<ValueType> M1(N * kdim[1], kdim[0], kern_value.begin(), false);
  1164. for (Integer l0 = 0; l0 < M1.Dim(0); l0++) { // Transpose
  1165. for (Integer l1 = 0; l1 < M1.Dim(1); l1++) {
  1166. M1[l0][l1] = M0[l1][l0];
  1167. }
  1168. }
  1169. }
  1170. }
  1171. { // Set Update M
  1172. Matrix<ValueType> Mkern(eval_mesh[SUBDIM - 1].Dim(), kern_value.Dim() / eval_mesh[SUBDIM - 1].Dim(), kern_value.begin(), false);
  1173. for (Integer k = SUBDIM - 1; k >= 0; k--) { // Compute v0
  1174. Matrix<ValueType> Mpoly(order, eval_mesh[k].Dim(), eval_poly[k].begin(), false);
  1175. v1.ReInit(Mpoly.Dim(0) * Mkern.Dim(1));
  1176. Matrix<ValueType> Mcoef(Mpoly.Dim(0), Mkern.Dim(1), v1.begin(), false);
  1177. Matrix<ValueType>::GEMM(Mcoef, Mpoly, Mkern);
  1178. v0.ReInit(v1.Dim());
  1179. Matrix<ValueType> Mt(Mkern.Dim(1), Mpoly.Dim(0), v0.begin(), false);
  1180. for (Integer l0 = 0; l0 < Mt.Dim(0); l0++) { // Transpose
  1181. for (Integer l1 = 0; l1 < Mt.Dim(1); l1++) {
  1182. Mt[l0][l1] = Mcoef[l1][l0];
  1183. }
  1184. }
  1185. if (k > 0) { // Reinit Mkern
  1186. Mkern.ReInit(eval_mesh[k - 1].Dim(), v0.Dim() / eval_mesh[k - 1].Dim(), v0.begin(), false);
  1187. }
  1188. }
  1189. assert(v0.Dim() == Mtensor.Dim(0) * Mtensor.Dim(1));
  1190. for (Integer k = 0; k < v0.Dim(); k++) { // Update M
  1191. Mtensor[0][k] += v0[k];
  1192. }
  1193. }
  1194. }
  1195. if (r[i0] < 0.0) break;
  1196. }
  1197. }
  1198. Mtensor = Mtensor.Transpose();
  1199. { // Set Mcoeff
  1200. if (Mcoeff.Dim(0) != kdim[1] || Mcoeff.Dim(1) != kdim[0] * Ncoeff) {
  1201. Mcoeff.ReInit(kdim[1], kdim[0] * Ncoeff);
  1202. }
  1203. Vector<ValueType> Mtensor_(Mtensor.Dim(0) * Mtensor.Dim(1), Mtensor.begin(), false);
  1204. Vector<ValueType> Mcoeff_(Mcoeff.Dim(0) * Mcoeff.Dim(1), Mcoeff.begin(), false);
  1205. tensor2coeff<SUBDIM>(order, Mtensor_, Mcoeff_);
  1206. }
  1207. }
  1208. static void diff_1d(Integer order, Matrix<ValueType>* M) {
  1209. Vector<ValueType> nodes;
  1210. Nodes<1>(order, nodes);
  1211. Integer N = nodes.Dim();
  1212. Matrix<ValueType> M0(N, N);
  1213. for (Integer i = 0; i < N; i++) {
  1214. for (Integer j = 0; j < N; j++) {
  1215. M0[i][j] = 0;
  1216. for (Integer l = 0; l < N; l++) {
  1217. if (l != i) {
  1218. ValueType Mij = 1;
  1219. for (Integer k = 0; k < N; k++) {
  1220. if (k != i) {
  1221. if (l == k) {
  1222. Mij *= 1 / (nodes[i] - nodes[k]);
  1223. } else {
  1224. Mij *= (nodes[j] - nodes[k]) / (nodes[i] - nodes[k]);
  1225. }
  1226. }
  1227. }
  1228. M0[i][j] += Mij;
  1229. }
  1230. }
  1231. }
  1232. }
  1233. Vector<ValueType> p;
  1234. Derived::EvalBasis1D(order, nodes, p);
  1235. Matrix<ValueType> Mp(order, N, p.begin(), false);
  1236. M0 = Mp * M0;
  1237. Vector<ValueType> coeff;
  1238. Approx<1>(order, Vector<ValueType>(M0.Dim(0) * M0.Dim(1), M0.begin(), false), coeff);
  1239. (*M) = Matrix<ValueType>(M0.Dim(0), coeff.Dim() / M0.Dim(0), coeff.begin(), false);
  1240. }
  1241. friend Derived;
  1242. };
  1243. template <class ValueType> class ChebBasis : public BasisInterface<ValueType, ChebBasis<ValueType>> {
  1244. private:
  1245. ChebBasis();
  1246. static void Nodes1D(Integer order, Vector<ValueType>& nodes) { BasisInterface<ValueType, ChebBasis<ValueType>>::cheb_nodes_1d(order, nodes); }
  1247. /**
  1248. * \brief Returns the values of all Chebyshev polynomials up to degree d,
  1249. * evaluated at points in the input vector. Output format:
  1250. * { T0[x[0]], ..., T0[x[n-1]], T1[x[0]], ..., Td[x[n-1]] }
  1251. */
  1252. static void EvalBasis1D(Integer order, const Vector<ValueType>& x, Vector<ValueType>& y) { BasisInterface<ValueType, ChebBasis<ValueType>>::cheb_basis_1d(order, x, y); }
  1253. friend BasisInterface<ValueType, ChebBasis<ValueType>>;
  1254. };
  1255. } // end namespace
  1256. #endif //_SCTL_CHEB_UTILS_HPP_