cheb_utils.hpp 51 KB

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