singular_correction.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #ifndef _SINGULAR_CORRECTION_HPP_
  2. #define _SINGULAR_CORRECTION_HPP_
  3. #include <biest/kernel.hpp>
  4. #include <biest/mat.hpp>
  5. #include <sctl.hpp>
  6. namespace biest {
  7. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> class SingularCorrection {
  8. static constexpr sctl::Integer COORD_DIM = 3;
  9. static constexpr sctl::Integer PATCH_DIM = 2 * PATCH_DIM0 + 1; // <= 55 (odd)
  10. //static constexpr sctl::Integer RAD_DIM = 18; // <= 18
  11. static constexpr sctl::Integer ANG_DIM = 2 * RAD_DIM; // <= 39
  12. static constexpr sctl::Integer INTERP_ORDER = 12;
  13. static constexpr sctl::Integer Ngrid = PATCH_DIM * PATCH_DIM;
  14. static constexpr sctl::Integer Npolar = RAD_DIM * ANG_DIM;
  15. static_assert(INTERP_ORDER <= PATCH_DIM, "Must have INTERP_ORDER <= PATCH_DIM");
  16. static std::vector<Real> qx, qw;
  17. static std::vector<Real> Gpou_, Ppou_;
  18. static std::vector<sctl::Integer> I_G2P;
  19. static std::vector<Real> M_G2P;
  20. public:
  21. SingularCorrection() { InitPrecomp(); }
  22. void Setup( sctl::Integer TRG_SKIP, sctl::Long Nt, sctl::Long Np, const sctl::Vector<Real>& SrcCoord, const sctl::Vector<Real>& SrcGrad, sctl::Long t_, sctl::Long p_, const KernelFunction<Real,COORD_DIM,KDIM0,KDIM1>& ker, Real normal_scal);
  23. void operator()(const sctl::Vector<Real>& SrcDensity, sctl::Vector<Real>& Potential) const;
  24. private:
  25. void SetPatch(sctl::Vector<Real>& out, sctl::Long t0, sctl::Long p0, const sctl::Vector<Real>& in, sctl::Long Nt, sctl::Long Np) const;
  26. static void InitPrecomp();
  27. sctl::StaticArray<Real, KDIM0 * Ngrid * KDIM1> MGrid_;
  28. sctl::Long TRG_SKIP, Nt, Np, t, p;
  29. };
  30. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> std::vector<Real> SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::qx;
  31. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> std::vector<Real> SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::qw;
  32. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> std::vector<Real> SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::Gpou_;
  33. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> std::vector<Real> SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::Ppou_;
  34. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> std::vector<Real> SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::M_G2P;
  35. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> std::vector<sctl::Integer> SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::I_G2P;
  36. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> void SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::InitPrecomp() {
  37. if (!qx.size()) { // Set qx, qw
  38. sctl::Integer order = RAD_DIM;
  39. std::vector<Real> qx_(order);
  40. std::vector<Real> qw_(order);
  41. if (1) { // Set qx_, qw_
  42. sctl::Vector<Real> qx__(qx_.size(), sctl::Ptr2Itr<Real>(qx_.data(), qx_.size()), false);
  43. sctl::Vector<Real> qw__(qw_.size(), sctl::Ptr2Itr<Real>(qw_.data(), qw_.size()), false);
  44. sctl::ChebBasis<Real>::quad_rule(order, qx__, qw__);
  45. } else { // Trapezoidal rule (does not work for Helmholtz imaginary part)
  46. for (sctl::Long i = 0; i < order; i++) {
  47. qx_[i] = (2 * i + 1) / (Real)(2 * order);
  48. qw_[i] = 1 / (Real)order;
  49. }
  50. }
  51. #pragma omp critical (SingularCorrection_InitPrecomp)
  52. if (!qx.size()) {
  53. qx.swap(qx_);
  54. qw.swap(qw_);
  55. }
  56. }
  57. if (!Gpou_.size()) { // Set Gpou, Ppou
  58. auto pou = [&](Real r) {
  59. Real a = 0;
  60. Real b = 1;
  61. //return r < a ? 1 : (r >= b ? 0 : sctl::exp<Real>(1 - 1 / (1 - ((r-a)/(b-a)) * ((r-a)/(b-a)))) );
  62. //return r >= b ? 0 : (r < a ? 1 : sctl::exp<Real>(2*sctl::exp<Real>(-(b-a)/(r-a)) / ((r-a)/(b-a)-1))); // BRUNO AND KUNYANSKY
  63. if (PATCH_DIM > 45) {
  64. return r < a ? 1 : sctl::exp<Real>(-(Real)36 * sctl::pow<10,Real>((r-a)/(b-a)));
  65. } else if (PATCH_DIM > 20) {
  66. return r < a ? 1 : sctl::exp<Real>(-(Real)36 * sctl::pow< 8,Real>((r-a)/(b-a)));
  67. } else {
  68. return r < a ? 1 : sctl::exp<Real>(-(Real)36 * sctl::pow< 6,Real>((r-a)/(b-a)));
  69. }
  70. };
  71. std::vector<Real> Gpou__(Ngrid);
  72. sctl::Vector<Real> Gpou(Gpou__.size(), sctl::Ptr2Itr<Real>(Gpou__.data(), Gpou__.size()), false);
  73. sctl::Integer PATCH_RAD = (PATCH_DIM - 1) / 2;
  74. SCTL_ASSERT(PATCH_DIM == 2 * PATCH_RAD + 1);
  75. Real h = 1 / (Real)PATCH_RAD;
  76. for (sctl::Integer i = 0; i < PATCH_DIM; i++){
  77. for (sctl::Integer j = 0; j < PATCH_DIM; j++){
  78. Real dr[2] = {(i - PATCH_RAD) * h, (j - PATCH_RAD) * h};
  79. Real r = sqrt(dr[0] * dr[0] + dr[1] * dr[1]);
  80. Gpou[i * PATCH_DIM + j] = -pou(r);
  81. }
  82. }
  83. std::vector<Real> Ppou__(Npolar);
  84. sctl::Vector<Real> Ppou(Ppou__.size(), sctl::Ptr2Itr<Real>(Ppou__.data(), Ppou__.size()), false);
  85. Real dt = 2 * sctl::const_pi<Real>() / ANG_DIM;
  86. for (sctl::Integer i = 0; i < RAD_DIM; i++){
  87. for (sctl::Integer j = 0; j < ANG_DIM; j++){
  88. Real dr = qw[i] * PATCH_RAD;
  89. Real rdt = qx[i] * PATCH_RAD * dt;
  90. Ppou[i * ANG_DIM + j] = pou(qx[i]) * dr * rdt;
  91. }
  92. }
  93. #pragma omp critical (SingularCorrection_InitPrecomp)
  94. if (!Gpou_.size()) {
  95. Gpou_.swap(Gpou__);
  96. Ppou_.swap(Ppou__);
  97. if (0) {
  98. // this does not give accurate error estimate for trapezoidal rule
  99. // since |r| is not smooth.
  100. Real sum0=0, sum1=0;
  101. for (auto a : Ppou_) sum0 += a;
  102. for (auto a : Gpou_) sum1 += a;
  103. std::cout<<"POU error: "<<(double)fabs((sum0+sum1)/(fabs(sum0)+fabs(sum1)))<<'\n';
  104. }
  105. }
  106. }
  107. if (!I_G2P.size()) { // Set I_G2P, M_G2P
  108. std::vector<sctl::Integer> I_G2P__(Npolar);
  109. std::vector<Real> M_G2P__(Npolar * INTERP_ORDER * INTERP_ORDER);
  110. sctl::Vector<sctl::Integer> I_G2P_(I_G2P__.size(), sctl::Ptr2Itr<sctl::Integer>(I_G2P__.data(), I_G2P__.size()), false);
  111. sctl::Vector<Real> M_G2P_(M_G2P__.size(), sctl::Ptr2Itr<Real>(M_G2P__.data(), M_G2P__.size()), false);
  112. Real h = 1 / (Real)(INTERP_ORDER - 1);
  113. auto lagrange_interp = [&](Real x0, Real x1, sctl::Integer i0, sctl::Integer i1) { // (x0,x1) \in [0,1]x[0,1]
  114. Real p=1;
  115. Real z0 = i0 * h;
  116. Real z1 = i1 * h;
  117. for (sctl::Integer j0 = 0; j0 < INTERP_ORDER; j0++) {
  118. if (j0 != i0) {
  119. Real y0 = j0 * h;
  120. p *= (x0 - y0) / (z0 - y0);
  121. }
  122. }
  123. for (sctl::Integer j1 = 0; j1 < INTERP_ORDER; j1++) {
  124. if (j1 != i1) {
  125. Real y1 = j1 * h;
  126. p *= (x1 - y1) / (z1 - y1);
  127. }
  128. }
  129. return p;
  130. };
  131. Real h_ang = 2 * sctl::const_pi<Real>() / ANG_DIM;
  132. for (sctl::Integer i0 = 0; i0 < RAD_DIM; i0++) {
  133. for (sctl::Integer i1 = 0; i1 < ANG_DIM; i1++) {
  134. Real x0 = (Real)0.5 + (Real)0.5 * qx[i0] * cos(h_ang * i1);
  135. Real x1 = (Real)0.5 + (Real)0.5 * qx[i0] * sin(h_ang * i1);
  136. sctl::Integer y0 = std::max<sctl::Integer>(0, std::min<sctl::Integer>((sctl::Integer)(x0 * (PATCH_DIM - 1) - (INTERP_ORDER - 1) / 2), PATCH_DIM - INTERP_ORDER));
  137. sctl::Integer y1 = std::max<sctl::Integer>(0, std::min<sctl::Integer>((sctl::Integer)(x1 * (PATCH_DIM - 1) - (INTERP_ORDER - 1) / 2), PATCH_DIM - INTERP_ORDER));
  138. Real z0 = (x0 * (PATCH_DIM - 1) - y0) * h;
  139. Real z1 = (x1 * (PATCH_DIM - 1) - y1) * h;
  140. I_G2P_[i0 * ANG_DIM + i1] = y0 * PATCH_DIM + y1;
  141. for (sctl::Integer j0 = 0; j0 < INTERP_ORDER; j0++) {
  142. for (sctl::Integer j1 = 0; j1 < INTERP_ORDER; j1++) {
  143. M_G2P_[(((i0 * ANG_DIM + i1) * INTERP_ORDER) + j0) * INTERP_ORDER + j1] = lagrange_interp(z0, z1, j0, j1);
  144. }
  145. }
  146. }
  147. }
  148. #pragma omp critical (SingularCorrection_InitPrecomp)
  149. if (!I_G2P.size()) {
  150. I_G2P.swap(I_G2P__);
  151. M_G2P.swap(M_G2P__);
  152. }
  153. }
  154. }
  155. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> void SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::Setup(sctl::Integer TRG_SKIP_, sctl::Long SrcNTor, sctl::Long SrcNPol, const sctl::Vector<Real>& SrcCoord, const sctl::Vector<Real>& SrcGrad, sctl::Long t_, sctl::Long p_, const KernelFunction<Real,COORD_DIM,KDIM0,KDIM1>& ker, Real normal_scal) {
  156. TRG_SKIP = TRG_SKIP_;
  157. Nt = SrcNTor;
  158. Np = SrcNPol;
  159. t = t_;
  160. p = p_;
  161. assert(KDIM0 == ker.Dim(0));
  162. assert(KDIM1 == ker.Dim(1));
  163. sctl::Matrix<Real> MGrid(KDIM0 * Ngrid, KDIM1, MGrid_, false);
  164. sctl::StaticArray<Real, COORD_DIM * Ngrid> G_ ;
  165. sctl::StaticArray<Real,2 * COORD_DIM * Ngrid> Gg_;
  166. sctl::StaticArray<Real, COORD_DIM * Ngrid> Gn_;
  167. sctl::StaticArray<Real, Ngrid> Ga_;
  168. sctl::StaticArray<Real, COORD_DIM * Npolar> P_ ;
  169. sctl::StaticArray<Real,2 * COORD_DIM * Npolar> Pg_;
  170. sctl::StaticArray<Real, COORD_DIM * Npolar> Pn_;
  171. sctl::StaticArray<Real, Npolar> Pa_;
  172. sctl::Vector<Real> G ( COORD_DIM * Ngrid, G_ , false);
  173. sctl::Vector<Real> Gg(2 * COORD_DIM * Ngrid, Gg_, false);
  174. sctl::Vector<Real> Gn( COORD_DIM * Ngrid, Gn_, false);
  175. sctl::Vector<Real> Ga( Ngrid, Ga_, false);
  176. sctl::Vector<Real> P ( COORD_DIM * Npolar, P_ , false);
  177. sctl::Vector<Real> Pg(2 * COORD_DIM * Npolar, Pg_, false);
  178. sctl::Vector<Real> Pn( COORD_DIM * Npolar, Pn_, false);
  179. sctl::Vector<Real> Pa( Npolar, Pa_, false);
  180. sctl::StaticArray<Real, COORD_DIM> TrgCoord_;
  181. sctl::Vector<Real> TrgCoord(COORD_DIM, TrgCoord_, false);
  182. for (sctl::Integer k = 0; k < COORD_DIM; k++) { // Set TrgCoord
  183. TrgCoord[k] = SrcCoord[(k * Nt + t) * Np + p];
  184. }
  185. SetPatch(G , t, p, SrcCoord , Nt, Np);
  186. SetPatch(Gg, t, p, SrcGrad , Nt, Np);
  187. Real invNt = 1 / (Real)Nt;
  188. Real invNp = 1 / (Real)Np;
  189. for (sctl::Integer i = 0; i < Ngrid; i++) {
  190. Real n0 = Gg[2 * Ngrid + i] * Gg[5 * Ngrid + i] - Gg[3 * Ngrid + i] * Gg[4 * Ngrid + i];
  191. Real n1 = Gg[4 * Ngrid + i] * Gg[1 * Ngrid + i] - Gg[5 * Ngrid + i] * Gg[0 * Ngrid + i];
  192. Real n2 = Gg[0 * Ngrid + i] * Gg[3 * Ngrid + i] - Gg[1 * Ngrid + i] * Gg[2 * Ngrid + i];
  193. Real r = sqrt(n0 * n0 + n1 * n1 + n2 * n2);
  194. Real inv_r = 1 / r;
  195. Gn[0 * Ngrid + i] = n0 * inv_r * normal_scal;
  196. Gn[1 * Ngrid + i] = n1 * inv_r * normal_scal;
  197. Gn[2 * Ngrid + i] = n2 * inv_r * normal_scal;
  198. Ga[i] = r * invNt * invNp;
  199. Gg[0 * Ngrid + i] *= invNt;
  200. Gg[2 * Ngrid + i] *= invNt;
  201. Gg[4 * Ngrid + i] *= invNt;
  202. Gg[1 * Ngrid + i] *= invNp;
  203. Gg[3 * Ngrid + i] *= invNp;
  204. Gg[5 * Ngrid + i] *= invNp;
  205. }
  206. { // Lagrange interpolation
  207. auto matvec = [&](sctl::Vector<Real>& Vout, const sctl::Vector<Real>& Vin, const std::vector<Real>& M) {
  208. sctl::Integer dof = Vin.Dim() / Ngrid;
  209. SCTL_ASSERT(Vin.Dim() == dof * Ngrid);
  210. SCTL_ASSERT(Vout.Dim() == dof * Npolar);
  211. Vout.SetZero();
  212. for (sctl::Integer k = 0; k < dof; k++) {
  213. for (sctl::Integer j = 0; j < Npolar; j++) {
  214. Real tmp = 0;
  215. sctl::ConstIterator<Real> M_ = sctl::Ptr2ConstItr<Real>(M.data(), M.size()) + j * INTERP_ORDER * INTERP_ORDER;
  216. sctl::ConstIterator<Real> Vin_ = Vin.begin() + k * Ngrid + I_G2P[j];
  217. if (1) {
  218. for (sctl::Integer i0 = 0; i0 < INTERP_ORDER; i0++) {
  219. for (sctl::Integer i1 = 0; i1 < INTERP_ORDER; i1++) {
  220. tmp += M_[i0 * INTERP_ORDER + i1] * Vin_[i0 * PATCH_DIM + i1];
  221. }
  222. }
  223. }
  224. if (0 && PATCH_DIM == 4) {
  225. tmp += M_[ 0] * Vin_[0*PATCH_DIM+0];
  226. tmp += M_[ 1] * Vin_[0*PATCH_DIM+1];
  227. tmp += M_[ 2] * Vin_[0*PATCH_DIM+2];
  228. tmp += M_[ 3] * Vin_[0*PATCH_DIM+3];
  229. tmp += M_[ 4] * Vin_[1*PATCH_DIM+0];
  230. tmp += M_[ 5] * Vin_[1*PATCH_DIM+1];
  231. tmp += M_[ 6] * Vin_[1*PATCH_DIM+2];
  232. tmp += M_[ 7] * Vin_[1*PATCH_DIM+3];
  233. tmp += M_[ 8] * Vin_[2*PATCH_DIM+0];
  234. tmp += M_[ 9] * Vin_[2*PATCH_DIM+1];
  235. tmp += M_[10] * Vin_[2*PATCH_DIM+2];
  236. tmp += M_[11] * Vin_[2*PATCH_DIM+3];
  237. tmp += M_[12] * Vin_[3*PATCH_DIM+0];
  238. tmp += M_[13] * Vin_[3*PATCH_DIM+1];
  239. tmp += M_[14] * Vin_[3*PATCH_DIM+2];
  240. tmp += M_[15] * Vin_[3*PATCH_DIM+3];
  241. }
  242. Vout[k * Npolar + j] = tmp;
  243. }
  244. }
  245. //sctl::Profile::Add_FLOP(dof*Npolar*INTERP_ORDER*INTERP_ORDER);
  246. };
  247. matvec(P , G , M_G2P);
  248. matvec(Pg, Gg , M_G2P);
  249. for (sctl::Integer i = 0; i < Npolar; i++) { // Compute Pn, Pa
  250. Real n0 = Pg[2 * Npolar + i] * Pg[5 * Npolar + i] - Pg[3 * Npolar + i] * Pg[4 * Npolar + i];
  251. Real n1 = Pg[4 * Npolar + i] * Pg[1 * Npolar + i] - Pg[5 * Npolar + i] * Pg[0 * Npolar + i];
  252. Real n2 = Pg[0 * Npolar + i] * Pg[3 * Npolar + i] - Pg[1 * Npolar + i] * Pg[2 * Npolar + i];
  253. Real r = sqrt(n0 * n0 + n1 * n1 + n2 * n2);
  254. n0 /= r;
  255. n1 /= r;
  256. n2 /= r;
  257. Pn[0 * Npolar + i] = n0 * normal_scal;
  258. Pn[1 * Npolar + i] = n1 * normal_scal;
  259. Pn[2 * Npolar + i] = n2 * normal_scal;
  260. Pa[i] = r;
  261. }
  262. }
  263. { // Subtract singular part from U
  264. { // Subtract singular part from U
  265. #ifndef DISABLE_FAR_FIELD
  266. ker.BuildMatrix(G, Gn, TrgCoord, MGrid);
  267. for (sctl::Integer k0 = 0; k0 < KDIM0; k0++) { // apply weights (Ga * Gpou)
  268. for (sctl::Integer k1 = 0; k1 < KDIM1; k1++) {
  269. for (sctl::Integer i = 0; i < Ngrid; i++) {
  270. MGrid[k0 * Ngrid + i][k1] *= Ga[i] * Gpou_[i];
  271. }
  272. }
  273. }
  274. #else
  275. MGrid.SetZero();
  276. #endif
  277. }
  278. { // Add singular part to U
  279. sctl::Matrix<Real> MPolar(KDIM0 * Npolar, KDIM1);
  280. ker.BuildMatrix(P, Pn, TrgCoord, MPolar); // MPolar <-- ker(P, Pn, TrgCoord)
  281. for (sctl::Integer k0 = 0; k0 < KDIM0; k0++) { // MPolar <-- Mpolar * Pa * Ppou
  282. for (sctl::Integer k1 = 0; k1 < KDIM1; k1++) {
  283. for (sctl::Integer i = 0; i < Npolar; i++) {
  284. MPolar[k0 * Npolar + i][k1] *= Pa[i] * Ppou_[i];
  285. }
  286. }
  287. }
  288. for (sctl::Integer j = 0; j < Npolar; j++) { // MGrid <-- MPolar * Transpose(M_G2P)
  289. sctl::Iterator<Real> MGrid_ = MGrid[I_G2P[j]];
  290. sctl::ConstIterator<Real> MPolar_ = MPolar[j];
  291. sctl::ConstIterator<Real> M_G2P_ = sctl::Ptr2ConstItr<Real>(&M_G2P[0], M_G2P.size()) + j * INTERP_ORDER * INTERP_ORDER;
  292. for (sctl::Integer i0 = 0; i0 < INTERP_ORDER; i0++) {
  293. for (sctl::Integer i1 = 0; i1 < INTERP_ORDER; i1++) {
  294. Real M_G2P__ = M_G2P_[i0 * INTERP_ORDER + i1];
  295. sctl::Iterator<Real> MGrid__ = MGrid_ + (i0 * PATCH_DIM + i1) * KDIM1;
  296. for (sctl::Integer k0 = 0; k0 < KDIM0; k0++) {
  297. for (sctl::Integer k1 = 0; k1 < KDIM1; k1++) {
  298. MGrid__[k0 * Ngrid * KDIM1 + k1] += M_G2P__ * MPolar_[k0 * Npolar * KDIM1 + k1];
  299. }
  300. }
  301. }
  302. }
  303. }
  304. }
  305. }
  306. }
  307. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> void SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::operator()(const sctl::Vector<Real>& SrcDensity, sctl::Vector<Real>& Potential) const {
  308. sctl::StaticArray<Real, KDIM0*Ngrid> GF_;
  309. sctl::Vector<Real> GF(KDIM0 * Ngrid, GF_, false);
  310. SetPatch(GF, t, p, SrcDensity, Nt, Np);
  311. sctl::StaticArray<Real,KDIM1> U_;
  312. sctl::Matrix<Real> U(1,KDIM1, U_, false);
  313. { // Compute correction U
  314. const sctl::Matrix<Real> Vin(1, GF.Dim(), GF.begin(), false);
  315. const sctl::Matrix<Real> MGrid(KDIM0 * Ngrid, KDIM1, (sctl::Iterator<Real>)(sctl::ConstIterator<Real>)MGrid_, false);
  316. sctl::Matrix<Real>::GEMM(U, Vin, MGrid);
  317. }
  318. for (sctl::Integer k = 0; k < KDIM1; k++) { // Add correction to Potential
  319. Potential[(k * (Nt/TRG_SKIP) + (t/TRG_SKIP)) * (Np/TRG_SKIP) + (p/TRG_SKIP)] += U[0][k];
  320. }
  321. }
  322. template <class Real, sctl::Integer PATCH_DIM0, sctl::Integer RAD_DIM, sctl::Integer KDIM0, sctl::Integer KDIM1> void SingularCorrection<Real,PATCH_DIM0,RAD_DIM,KDIM0,KDIM1>::SetPatch(sctl::Vector<Real>& out, sctl::Long t0, sctl::Long p0, const sctl::Vector<Real>& in, sctl::Long Nt, sctl::Long Np) const {
  323. SCTL_ASSERT(Nt >= PATCH_DIM);
  324. SCTL_ASSERT(Np >= PATCH_DIM);
  325. sctl::Long dof = in.Dim() / (Nt * Np);
  326. SCTL_ASSERT(in.Dim() == dof * Nt * Np);
  327. SCTL_ASSERT(out.Dim() == dof * Ngrid);
  328. sctl::Integer tt0 = t0 - (PATCH_DIM - 1) / 2;
  329. sctl::Integer pp0 = p0 - (PATCH_DIM - 1) / 2;
  330. for (sctl::Long k = 0; k < dof; k++) {
  331. for (sctl::Long i = 0; i < PATCH_DIM; i++) {
  332. sctl::Long t = tt0 + i;
  333. if (t >= Nt) t = t - Nt;
  334. if (t < 0) t = t + Nt;
  335. sctl::ConstIterator<Real> in_ = in.begin() + (k * Nt + t) * Np;
  336. sctl::Iterator<Real> out_ = out.begin() + (k * PATCH_DIM + i) * PATCH_DIM;
  337. for (sctl::Long j = 0; j < PATCH_DIM; j++) {
  338. sctl::Long p = pp0 + j;
  339. if (p >= Np) p = p - Np;
  340. if (p < 0) p = p + Np;
  341. out_[j] = in_[p];
  342. }
  343. }
  344. }
  345. }
  346. }
  347. #endif //_SINGULAR_CORRECTION_HPP_