bie_solvers.hpp 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669
  1. #ifndef _BIE_SOLVERS_HPP_
  2. #define _BIE_SOLVERS_HPP_
  3. #include <biest/boundary_integ_op.hpp>
  4. #include <biest/surface_op.hpp>
  5. #include <biest/surface.hpp>
  6. #include <biest/kernel.hpp>
  7. #include <sctl.hpp>
  8. namespace biest {
  9. template <class Real, sctl::Integer UPSAMPLE = 1, sctl::Integer PATCH_DIM0 = 24, sctl::Integer RAD_DIM = 35> class VacuumField {
  10. static constexpr sctl::Integer COORD_DIM = 3;
  11. public:
  12. static void Compute(sctl::Vector<Real>& B, sctl::Vector<Real>& J, Real tor_flux, Real pol_flux, const sctl::Vector<Surface<Real>>& Svec, const sctl::Comm& comm, Real gmres_tol, sctl::Long gmres_iter) {
  13. sctl::Vector<sctl::Vector<Real>> B_, J_;
  14. sctl::Vector<Real> tor_flux_, pol_flux_;
  15. ComputeHelper(B_, J_, tor_flux_, pol_flux_, Svec, comm, gmres_tol, gmres_iter);
  16. if (Svec.Dim() == 1) {
  17. B = B_[0] * tor_flux / tor_flux_[0];
  18. J = J_[0] * tor_flux / tor_flux_[0];
  19. } else if (Svec.Dim() == 2) {
  20. Real alpha = (tor_flux * pol_flux_[1] - pol_flux * tor_flux_[1]) / (tor_flux_[0] * pol_flux_[1] - tor_flux_[1] * pol_flux_[0]);
  21. Real beta = (pol_flux * tor_flux_[0] - tor_flux * pol_flux_[0]) / (tor_flux_[0] * pol_flux_[1] - tor_flux_[1] * pol_flux_[0]);
  22. B = B_[0] * alpha + B_[1] * beta;
  23. J = J_[0] * alpha + J_[1] * beta;
  24. }
  25. }
  26. static void EvalOffSurface(sctl::Vector<Real>& Btrg, const sctl::Vector<Real>& Xtrg, sctl::Vector<Surface<Real>> Svec, sctl::Vector<Real> J0, const sctl::Comm& comm) {
  27. sctl::Vector<sctl::Vector<Real>> Xsrc, dXsrc, Xn_src, Xa_src, J;
  28. { // Upsample
  29. sctl::Long Nsurf = Svec.Dim();
  30. Xsrc .ReInit(Nsurf);
  31. dXsrc .ReInit(Nsurf);
  32. Xn_src.ReInit(Nsurf);
  33. Xa_src.ReInit(Nsurf);
  34. J.ReInit(Nsurf);
  35. sctl::Long dsp = 0;
  36. for (sctl::Long i = 0; i < Nsurf; i++) {
  37. const auto& S = Svec[i];
  38. sctl::Long Nt0 = S.NTor();
  39. sctl::Long Np0 = S.NPol();
  40. sctl::Long Nup = Nt0*Np0*UPSAMPLE*UPSAMPLE;
  41. SurfaceOp<Real> Sop(comm, Nt0*UPSAMPLE, Np0*UPSAMPLE);
  42. Sop.Upsample(S.Coord(), Nt0, Np0, Xsrc[i], Nt0*UPSAMPLE, Np0*UPSAMPLE);
  43. Sop.Grad2D(dXsrc[i], Xsrc[i]);
  44. Sop.SurfNormalAreaElem(&Xn_src[i], &Xa_src[i], dXsrc[i], &Xsrc[i]);
  45. sctl::Vector<Real> J0_(COORD_DIM*Nt0*Np0, J0.begin()+COORD_DIM*dsp, false);
  46. Sop.Upsample(J0_, Nt0, Np0, J[i], Nt0*UPSAMPLE, Np0*UPSAMPLE);
  47. for (sctl::Long j = 0; j < Nup; j++) { // J <-- J * Xa
  48. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  49. J[i][k * Nup + j] *= Xa_src[i][j];
  50. }
  51. }
  52. dsp += Nt0 * Np0;
  53. }
  54. }
  55. { // Compute Btrg at Xtrg
  56. sctl::Vector<Real> X = Xtrg, B;
  57. sctl::Matrix<Real>(COORD_DIM, X.Dim()/COORD_DIM, X.begin(), false) = sctl::Matrix<Real>(X.Dim()/COORD_DIM, COORD_DIM, X.begin(), false).Transpose();
  58. ComputeFarField(B, X, Xsrc, Xn_src, J);
  59. sctl::Matrix<Real>(B.Dim()/COORD_DIM, COORD_DIM, B.begin(), false) = sctl::Matrix<Real>(COORD_DIM, B.Dim()/COORD_DIM, B.begin(), false).Transpose();
  60. Btrg = B;
  61. }
  62. }
  63. static void test(sctl::Long upsample, const sctl::Comm& comm) {
  64. sctl::Vector<Real> B, J;
  65. sctl::Vector<Surface<Real>> Svec;
  66. Svec.PushBack(Surface<Real>( 50*upsample+1, 20*upsample+1, SurfType::AxisymCircleWide));
  67. Svec.PushBack(Surface<Real>(100*upsample+1, 20*upsample+1, SurfType::Quas3));
  68. Compute(B, J, 1, 1, Svec, comm, 1e-8, 30);
  69. WriteVTK("B", Svec, B);
  70. }
  71. private:
  72. static Real max_norm(const sctl::Vector<Real>& x) {
  73. Real err = 0;
  74. for (const auto& a : x) err = std::max(err, sctl::fabs<Real>(a));
  75. return err;
  76. }
  77. static void ComputeFarField(sctl::Vector<Real>& B, const sctl::Vector<Real>& Xt, const sctl::Vector<sctl::Vector<Real>>& Xsrc, const sctl::Vector<sctl::Vector<Real>>& Xn_src, const sctl::Vector<sctl::Vector<Real>>& J) {
  78. sctl::Long Nsurf = Xsrc.Dim();
  79. sctl::Vector<sctl::Long> SurfDim(Nsurf), SurfDsp(Nsurf);
  80. for (sctl::Long i = 0; i < Nsurf; i++) { // Set SurfDim, SurfDsp
  81. SurfDim[i] = Xsrc[i].Dim() / COORD_DIM;
  82. if (i) SurfDsp[i] = SurfDsp[i-1] + SurfDim[i-1];
  83. else SurfDsp[i] = 0;
  84. }
  85. sctl::Long Nt = Xt.Dim() / COORD_DIM;
  86. SCTL_ASSERT(Xt.Dim() == Nt * COORD_DIM);
  87. if (B.Dim() != COORD_DIM * Nt) B.ReInit(COORD_DIM * Nt);
  88. B = 0;
  89. const auto& ker_biot_savart = BiotSavart3D<Real>::FxU();
  90. for (sctl::Long i = 0; i < Nsurf; i++) {
  91. ker_biot_savart(Xsrc[i], Xn_src[i], J[i], Xt, B);
  92. }
  93. }
  94. static void ComputeHelper(sctl::Vector<sctl::Vector<Real>>& B, sctl::Vector<sctl::Vector<Real>>& J, sctl::Vector<Real>& tor_flux, sctl::Vector<Real>& pol_flux, const sctl::Vector<Surface<Real>>& Svec, const sctl::Comm& comm, Real gmres_tol, sctl::Long gmres_iter) {
  95. sctl::Long Nsurf = Svec.Dim();
  96. sctl::Vector<sctl::Long> SurfDim(Nsurf), SurfDsp(Nsurf);
  97. for (sctl::Long i = 0; i < Nsurf; i++) { // Set SurfDim, SurfDsp
  98. SurfDim[i] = Svec[i].NTor() * Svec[i].NPol();
  99. if (i) SurfDsp[i] = SurfDsp[i-1] + SurfDim[i-1];
  100. else SurfDsp[i] = 0;
  101. }
  102. sctl::Vector<Real> SurfArea(Svec.Dim());
  103. sctl::Vector<sctl::Vector<Real>> dX(Svec.Dim()), d2X(Svec.Dim()), Xn(Svec.Dim()), Xa(Svec.Dim());
  104. for (sctl::Long i = 0; i < Svec.Dim(); i++) { // Set dX, Xn, Xa
  105. const auto& S = Svec[i];
  106. sctl::Long Nt = S.NTor();
  107. sctl::Long Np = S.NPol();
  108. SurfaceOp<Real> surf_op(comm, Nt, Np);
  109. surf_op.Grad2D(dX[i], S.Coord());
  110. surf_op.Grad2D(d2X[i], dX[i]);
  111. surf_op.SurfNormalAreaElem(&Xn[i], &Xa[i], dX[i], &S.Coord());
  112. SurfArea[i] = 0;
  113. for (const auto& da : Xa[i]) SurfArea[i] += da;
  114. }
  115. { // Set normal to outer-normal
  116. sctl::Long OuterSurfIdx = 0, InnerSurfIdx = 0;
  117. for (sctl::Long i = 0; i < Svec.Dim(); i++) { // TODO: this is not reliable, use the normal direction to do this
  118. if (SurfArea[i] < SurfArea[InnerSurfIdx]) InnerSurfIdx = i;
  119. if (SurfArea[i] > SurfArea[OuterSurfIdx]) OuterSurfIdx = i;
  120. }
  121. for (sctl::Long i = 0; i < Svec.Dim(); i++) { // Set normal to outer-normal
  122. Real scal = 0;
  123. if (i == InnerSurfIdx) scal = -1;
  124. if (i == OuterSurfIdx) scal = 1;
  125. Xn[i] *= scal;
  126. }
  127. }
  128. sctl::Profile::Tic("Setup", &comm);
  129. const auto& ker_laplace = Laplace3D<Real>::FxU();
  130. const auto& ker_lap_grad = Laplace3D<Real>::FxdU();
  131. const auto& ker_biot_savart = BiotSavart3D<Real>::FxU();
  132. BoundaryIntegralOp<Real,3,3,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_biot_savart(comm);
  133. BoundaryIntegralOp<Real,1,3,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_lap_grad(comm);
  134. BoundaryIntegralOp<Real,1,1,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_laplace(comm);
  135. BI_biot_savart.SetupSingular(Svec, ker_biot_savart);
  136. BI_lap_grad.SetupSingular(Svec, ker_lap_grad);
  137. BI_laplace.SetupSingular(Svec, ker_laplace);
  138. sctl::Profile::Toc();
  139. sctl::Profile::Tic("ComputeJ", &comm);
  140. sctl::Vector<sctl::Vector<Real>> J0(Nsurf);
  141. auto ComputeJ = [&Svec,&SurfDim,&SurfDsp,&dX,&d2X,&Xn,&comm](sctl::Vector<Real>& J, sctl::Integer Sidx, Real gmres_tol, sctl::Long max_iter) { // Set Jp
  142. const auto& S = Svec[Sidx];
  143. sctl::Long Nt = S.NTor();
  144. sctl::Long Np = S.NPol();
  145. sctl::Long N = Nt * Np;
  146. std::cout << "\033[1;31m";
  147. sctl::Vector<Real> V(COORD_DIM * N), DivV, InvLapDivV, GradInvLapDivV;
  148. for (sctl::Long i = 0; i < N; i++) { // Set V
  149. for (sctl::Long k =0; k < COORD_DIM; k++) {
  150. V[k * N + i] = dX[Sidx][(k*2+0) * N + i] + dX[Sidx][(k*2+1) * N + i];
  151. }
  152. }
  153. SurfaceOp<Real> surf_op(comm, Nt, Np);
  154. surf_op.SurfDiv(DivV, dX[Sidx], V);
  155. surf_op.GradInvSurfLap(GradInvLapDivV, dX[Sidx], d2X[Sidx], DivV, gmres_tol * max_norm(V) / max_norm(DivV), max_iter, 1.5);
  156. V = V - GradInvLapDivV;
  157. if (0) { // Print err
  158. surf_op.SurfDiv(DivV, dX[Sidx], V);
  159. Real err = 0;
  160. for (const auto x : DivV) err = std::max(err, fabs(x));
  161. std::cout<<err<<'\n';
  162. }
  163. std::cout<<"\033[0m";
  164. { // Set J
  165. sctl::Long Nsurf = SurfDim.Dim();
  166. J.ReInit(COORD_DIM * (SurfDim[Nsurf-1] + SurfDsp[Nsurf-1]));
  167. J = 0;
  168. sctl::Vector<Real> J_(COORD_DIM * SurfDim[Sidx], J.begin() + COORD_DIM * SurfDsp[Sidx], false);
  169. J_ = V;
  170. }
  171. };
  172. for (sctl::Long i = 0; i < Nsurf; i++) ComputeJ(J0[i], i, gmres_tol * 0.01, gmres_iter); //-1);
  173. sctl::Profile::Toc();
  174. sctl::Profile::Tic("ComputeB0", &comm);
  175. sctl::Vector<sctl::Vector<Real>> B0(Nsurf);
  176. auto eval_B0 = [Nsurf,&SurfDim,&SurfDsp,&Xn,&BI_biot_savart](sctl::Vector<Real>& B, const sctl::Vector<Real>& J) { // B <-- BiotSavart[J] - 0.5 * Xn x J
  177. sctl::Long N = J.Dim();
  178. sctl::Vector<Real> NcrossJ(N);
  179. for (sctl::Long i = 0; i < Nsurf; i++) { // Set NcrossJ
  180. sctl::Long N = SurfDim[i];
  181. const sctl::Vector<Real> J_(COORD_DIM * N, (sctl::Iterator<Real>)J.begin() + COORD_DIM * SurfDsp[i], false);
  182. sctl::Vector<Real> NcrossJ_(COORD_DIM * N, NcrossJ.begin() + COORD_DIM * SurfDsp[i], false);
  183. for (sctl::Long j = 0; j < N; j++) {
  184. sctl::StaticArray<Real, COORD_DIM> Xn_, V0_, nxV0_;
  185. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  186. Xn_[k] = Xn[i][k * N + j];
  187. V0_[k] = J_[k * N + j];
  188. }
  189. nxV0_[0] = Xn_[1] * V0_[2] - Xn_[2] * V0_[1];
  190. nxV0_[1] = Xn_[2] * V0_[0] - Xn_[0] * V0_[2];
  191. nxV0_[2] = Xn_[0] * V0_[1] - Xn_[1] * V0_[0];
  192. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  193. NcrossJ_[k * N + j] = nxV0_[k];
  194. }
  195. }
  196. }
  197. BI_biot_savart(B, J);
  198. B -= NcrossJ * 0.5;
  199. };
  200. for (sctl::Long i = 0; i < Nsurf; i++) eval_B0(B0[i], J0[i]);
  201. sctl::Profile::Toc();
  202. auto eval_B = [Nsurf,&SurfDim,SurfDsp,&Xn,&BI_lap_grad](sctl::Vector<Real>& B, const sctl::Vector<Real>& F) { // B <-- dG[F] + 0.5 * Xn * F
  203. if (B.Dim() != BI_lap_grad.Dim(1)) {
  204. B.ReInit(BI_lap_grad.Dim(1));
  205. B = 0;
  206. }
  207. BI_lap_grad(B, F);
  208. for (sctl::Long j = 0; j < Nsurf; j++) {
  209. sctl::Long N = SurfDim[j];
  210. sctl::Long offset = SurfDsp[j];
  211. for (sctl::Long i = 0; i < N; i++) { // B <-- B + 0.5 * Xn * F
  212. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  213. B[COORD_DIM*offset + k*N+i] += 0.5 * Xn[j][k*N+i] * F[offset + i];
  214. }
  215. }
  216. }
  217. };
  218. auto eval_BdotXn = [Nsurf,&SurfDim,SurfDsp,&Xn](sctl::Vector<Real>& BdotXn, const sctl::Vector<Real>& B) { // BdotXn <-- B . Xn
  219. sctl::Long N = SurfDsp[Nsurf-1] + SurfDim[Nsurf-1];
  220. if (BdotXn.Dim() != N) BdotXn.ReInit(N);
  221. for (sctl::Long j = 0; j < Nsurf; j++) {
  222. sctl::Long N = SurfDim[j];
  223. sctl::Long offset = SurfDsp[j];
  224. for (sctl::Long i = 0; i < N; i++) { // BdotXn = B . Xn
  225. BdotXn[offset + i] = 0;
  226. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  227. BdotXn[offset + i] += B[COORD_DIM*offset + k*N+i] * Xn[j][k*N+i];
  228. }
  229. }
  230. }
  231. };
  232. typename sctl::ParallelSolver<Real>::ParallelOp fn = [&eval_B,&eval_BdotXn](sctl::Vector<Real>* BdotXn, const sctl::Vector<Real>& F) {
  233. SCTL_ASSERT(BdotXn);
  234. sctl::Vector<Real> B;
  235. eval_B(B, F);
  236. eval_BdotXn(*BdotXn, B);
  237. };
  238. auto compute_J = [&Nsurf,&SurfDim,&SurfDsp,&Xn](sctl::Vector<Real>& J, const sctl::Vector<Real>& B) { // J <-- Xn x B
  239. J.ReInit(B.Dim());
  240. for (sctl::Long i = 0; i < Nsurf; i++) {
  241. sctl::Long N = SurfDim[i];
  242. sctl::Long offset = SurfDsp[i];
  243. for (sctl::Long j = 0; j < N; j++) {
  244. sctl::StaticArray<Real, COORD_DIM> J_, B_, Xn_;
  245. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  246. B_[k] = B[COORD_DIM*offset + k*N + j];
  247. Xn_[k] = Xn[i][k*N + j];
  248. }
  249. J_[0] = Xn_[1]*B_[2] - Xn_[2]*B_[1];
  250. J_[1] = Xn_[2]*B_[0] - Xn_[0]*B_[2];
  251. J_[2] = Xn_[0]*B_[1] - Xn_[1]*B_[0];
  252. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  253. J[COORD_DIM*offset + k*N + j] = J_[k];
  254. }
  255. }
  256. }
  257. };
  258. sctl::Profile::Tic("Solve", &comm);
  259. { // Compute B, J
  260. B.ReInit(Nsurf);
  261. J.ReInit(Nsurf);
  262. sctl::Vector<Real> u0dotXn, F;
  263. sctl::ParallelSolver<Real> solver(comm, true);
  264. for (sctl::Long i = 0; i < Nsurf; i++) { // Compute B[i], J[i]
  265. B[i] = B0[i];
  266. eval_BdotXn(u0dotXn, B[i]);
  267. solver(&F, fn, u0dotXn*(-1), gmres_tol, gmres_iter);
  268. eval_B(B[i], F);
  269. compute_J(J[i], B[i]);
  270. }
  271. }
  272. sctl::Profile::Toc();
  273. auto compute_tor_circ = [&Svec,&dX](sctl::Vector<Real>* circ, const sctl::Vector<Real>& A, sctl::Long surf_id) {
  274. sctl::Long offset = 0;
  275. SCTL_ASSERT(surf_id < Svec.Dim());
  276. for (sctl::Long i = 0; i < surf_id; i++) {
  277. const auto& S = Svec[i];
  278. sctl::Long Nt = S.NTor();
  279. sctl::Long Np = S.NPol();
  280. offset += Nt * Np;
  281. }
  282. const auto& S = Svec[surf_id];
  283. sctl::Long Nt = S.NTor();
  284. sctl::Long Np = S.NPol();
  285. Real circ_ = 0;
  286. if (circ && circ->Dim() != Np) circ->ReInit(Np);
  287. for (sctl::Long p = 0; p < Np; p++) {
  288. Real integ0 = 0;
  289. for (sctl::Long t = 0; t < Nt; t++) {
  290. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  291. Real A0 = A[COORD_DIM*offset + k*Nt*Np + t*Np + p];
  292. Real dX_ = dX[surf_id][(2*k+0)*Nt*Np + t*Np + p];
  293. integ0 += A0 * dX_;
  294. }
  295. }
  296. if (circ) circ[0][p] = integ0 / Nt;
  297. circ_ += integ0;
  298. }
  299. return circ_ / (Nt*Np);
  300. };
  301. auto compute_pol_circ = [&Svec,&dX](sctl::Vector<Real>* circ, const sctl::Vector<Real>& A, sctl::Long surf_id) {
  302. sctl::Long offset = 0;
  303. SCTL_ASSERT(surf_id < Svec.Dim());
  304. for (sctl::Long i = 0; i < surf_id; i++) {
  305. const auto& S = Svec[i];
  306. sctl::Long Nt = S.NTor();
  307. sctl::Long Np = S.NPol();
  308. offset += Nt * Np;
  309. }
  310. const auto& S = Svec[surf_id];
  311. sctl::Long Nt = S.NTor();
  312. sctl::Long Np = S.NPol();
  313. Real circ_ = 0;
  314. if (circ && circ->Dim() != Nt) circ->ReInit(Nt);
  315. for (sctl::Long t = 0; t < Nt; t++) {
  316. Real integ0 = 0;
  317. for (sctl::Long p = 0; p < Np; p++) {
  318. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  319. Real A0 = A[COORD_DIM*offset + k*Nt*Np + t*Np + p];
  320. Real dX_ = dX[surf_id][(2*k+1)*Nt*Np + t*Np + p];
  321. integ0 += A0 * dX_;
  322. }
  323. }
  324. if (circ) circ[0][t] = integ0 / Np;
  325. circ_ += integ0;
  326. }
  327. return circ_ / (Nt*Np);
  328. };
  329. #ifdef BIEST_VERBOSE
  330. if (1) { // Check circulation error
  331. Real max_err = 0;
  332. for (sctl::Long i = 0; i < Svec.Dim(); i++) {
  333. sctl::Vector<Real> circ_t, circ_p;
  334. for (sctl::Long j = 0; j < Nsurf; j++) {
  335. Real circ_t_avg = compute_tor_circ(&circ_t, B[j], i);
  336. Real circ_p_avg = compute_pol_circ(&circ_p, B[j], i);
  337. for (const auto& x : circ_t) max_err = std::max(max_err, fabs(x-circ_t_avg));
  338. for (const auto& x : circ_p) max_err = std::max(max_err, fabs(x-circ_p_avg));
  339. }
  340. }
  341. std::cout<<"Circulation error: "<<max_err<<'\n';
  342. }
  343. if (0) { // Print error || B - BiotSavart(J) ||
  344. auto print_err = [&BI_biot_savart](const sctl::Vector<Real>& J, const sctl::Vector<Real>& B) {
  345. sctl::Vector<Real> B0;
  346. BI_biot_savart(B0, J*2);
  347. { // Print error
  348. auto Berr = B0 - B;
  349. Real max_err = 0, B_norm = 0;
  350. for (const auto& x : Berr) max_err = std::max(max_err, fabs(x));
  351. for (const auto& x : B) B_norm = std::max(B_norm, fabs(x));
  352. std::cout<<"Relative error : "<<max_err / B_norm<<'\n';
  353. }
  354. };
  355. for (sctl::Long i = 0; i < Nsurf; i++) print_err(J[i], B[i]);
  356. }
  357. #endif
  358. sctl::Profile::Tic("CompFlux", &comm);
  359. { // Compute flux
  360. sctl::Vector<Real> A;
  361. tor_flux.ReInit(Nsurf);
  362. pol_flux.ReInit(Nsurf);
  363. for (sctl::Long i = 0; i < Nsurf; i++) {
  364. BI_laplace(A, J[i]);
  365. tor_flux[i] = compute_pol_circ(nullptr, A, i);
  366. pol_flux[i] = compute_tor_circ(nullptr, A, i);
  367. }
  368. }
  369. sctl::Profile::Toc();
  370. }
  371. };
  372. template <class Real, sctl::Integer UPSAMPLE = 1, sctl::Integer PATCH_DIM0 = 24, sctl::Integer RAD_DIM = 35> class TaylorState {
  373. static constexpr sctl::Integer COORD_DIM = 3;
  374. public:
  375. static void Compute(sctl::Vector<Real>& B_out, Real tor_flux, Real pol_flux, Real lambda, const sctl::Vector<Surface<Real>>& Svec, const sctl::Comm& comm, Real gmres_tol, sctl::Long gmres_iter, Real LB_tol = 0.1, sctl::Vector<sctl::Vector<Real>>* m = nullptr, sctl::Vector<sctl::Vector<Real>>* sigma = nullptr) {
  376. sctl::Vector<sctl::Vector<Real>> B, m_, sigma_;
  377. ComputeHelper(B, m_, sigma_, lambda, Svec, comm, gmres_tol, gmres_iter, LB_tol);
  378. if (B.Dim() > 0) B_out = B[0] * tor_flux;
  379. if (B.Dim() > 1) B_out += B[1] * pol_flux;
  380. if (m && sigma) {
  381. *m = m_;
  382. *sigma = sigma_;
  383. }
  384. }
  385. static void EvalOffSurface(sctl::Vector<Real>& Btrg, const sctl::Vector<Real>& Xtrg, sctl::Vector<Surface<Real>> Svec, Real tor_flux, Real pol_flux, Real lambda, const sctl::Vector<sctl::Vector<Real>> m_, const sctl::Vector<sctl::Vector<Real>>& sigma_, const sctl::Comm& comm) {
  386. sctl::Vector<Real> m0, sigma0;
  387. if (Svec.Dim() > 0) m0 = m_[0] * tor_flux;
  388. if (Svec.Dim() > 1) m0 += m_[1] * pol_flux;
  389. if (Svec.Dim() > 0) sigma0 = sigma_[0] * tor_flux;
  390. if (Svec.Dim() > 1) sigma0 += sigma_[1] * pol_flux;
  391. sctl::Vector<sctl::Vector<Real>> Xsrc, dXsrc, Xn_src, Xa_src, m, sigma;
  392. { // Upsample
  393. sctl::Long Nsurf = Svec.Dim();
  394. Xsrc .ReInit(Nsurf);
  395. dXsrc .ReInit(Nsurf);
  396. Xn_src.ReInit(Nsurf);
  397. Xa_src.ReInit(Nsurf);
  398. sigma.ReInit(Nsurf);
  399. m.ReInit(Nsurf);
  400. sctl::Long dsp = 0;
  401. for (sctl::Long i = 0; i < Nsurf; i++) {
  402. const auto& S = Svec[i];
  403. sctl::Long Nt0 = S.NTor();
  404. sctl::Long Np0 = S.NPol();
  405. sctl::Long Nup = Nt0*Np0*UPSAMPLE*UPSAMPLE;
  406. SurfaceOp<Real> Sop(comm, Nt0*UPSAMPLE, Np0*UPSAMPLE);
  407. Sop.Upsample(S.Coord(), Nt0, Np0, Xsrc[i], Nt0*UPSAMPLE, Np0*UPSAMPLE);
  408. Sop.Grad2D(dXsrc[i], Xsrc[i]);
  409. Sop.SurfNormalAreaElem(&Xn_src[i], &Xa_src[i], dXsrc[i], &Xsrc[i]);
  410. sctl::Vector<Real> m0_(COORD_DIM*2*Nt0*Np0, m0.begin()+COORD_DIM*2*dsp, false);
  411. Sop.Upsample(m0_, Nt0, Np0, m[i], Nt0*UPSAMPLE, Np0*UPSAMPLE);
  412. for (sctl::Long j = 0; j < Nup; j++) { // m <-- m * Xa
  413. for (sctl::Long k = 0; k < COORD_DIM*2; k++) {
  414. m[i][k * Nup + j] *= Xa_src[i][j];
  415. }
  416. }
  417. sctl::Vector<Real> sigma0_(2*Nt0*Np0, sigma0.begin()+2*dsp, false);
  418. Sop.Upsample(sigma0_, Nt0, Np0, sigma[i], Nt0*UPSAMPLE, Np0*UPSAMPLE);
  419. for (sctl::Long j = 0; j < Nup; j++) { // sigma <-- sigma * Xa
  420. for (sctl::Long k = 0; k < 2; k++) {
  421. sigma[i][k * Nup + j] *= Xa_src[i][j];
  422. }
  423. }
  424. dsp += Nt0 * Np0;
  425. }
  426. }
  427. { // Compute Btrg at Xtrg
  428. sctl::Vector<Real> X = Xtrg, B;
  429. sctl::Matrix<Real>(COORD_DIM, X.Dim()/COORD_DIM, X.begin(), false) = sctl::Matrix<Real>(X.Dim()/COORD_DIM, COORD_DIM, X.begin(), false).Transpose();
  430. ComputeFarField(B, X, Xsrc, Xn_src, sigma, m, lambda);
  431. sctl::Matrix<Real>(B.Dim()/COORD_DIM, COORD_DIM, B.begin(), false) = sctl::Matrix<Real>(COORD_DIM, B.Dim()/COORD_DIM, B.begin(), false).Transpose();
  432. Btrg = B;
  433. }
  434. }
  435. static void test_conv(Real lambda, const sctl::Vector<Surface<Real>>& Svec_, sctl::Long upsample, Real gmres_tol, sctl::Long gmres_iter, const sctl::Comm& comm, Real LB_tol = 0.1) {
  436. auto append_vec = [](const sctl::Vector<Real>& a, const sctl::Vector<Real>& b) {
  437. sctl::Vector<Real> c(a.Dim()+b.Dim());
  438. for (sctl::Long i = 0; i < a.Dim(); i++) c[i] = a[i];
  439. for (sctl::Long i = 0; i < b.Dim(); i++) c[a.Dim() + i] = b[i];
  440. return c;
  441. };
  442. sctl::Vector<Surface<Real>> Svec;
  443. for (const auto& S0 : Svec_) {
  444. Surface<Real> S(S0.NTor()*upsample, S0.NPol()*upsample);
  445. SurfaceOp<Real>::Upsample(S0.Coord(), S0.NTor(), S0.NPol(), S.Coord(), S.NTor(), S.NPol());
  446. Svec.PushBack(S);
  447. }
  448. sctl::Vector<Real> B0;
  449. auto ref_sol = [&lambda](sctl::Vector<Real>& B, const sctl::Vector<Real>& Xt) {
  450. Helmholtz3D<Real> helm(lambda);
  451. const auto& ker_potn = helm.FxU();
  452. const auto& ker_grad = helm.FxdU();
  453. const auto pi = sctl::const_pi<Real>();
  454. sctl::Long N = 1000;
  455. sctl::Vector<Real> X(COORD_DIM * N);
  456. sctl::Vector<Real> dX(COORD_DIM * N);
  457. sctl::Vector<Real> Xn(COORD_DIM * N);
  458. for (sctl::Long i = 0; i < N; i++) {
  459. Real t = 2*pi*i/N;
  460. X[0*N+i] = 0; //5+sin(t);
  461. X[1*N+i] = 2*(cos(t) + 1); //5+cos(t);
  462. X[2*N+i] = 2*(sin(t)); //sin(t);
  463. dX[0*N+i] = 0; // cos(t);
  464. dX[1*N+i] =-sin(t)*2; //-sin(t);
  465. dX[2*N+i] = cos(t)*2; // cos(t);
  466. //X[0*N+i] = 0;
  467. //X[1*N+i] = 0;
  468. //X[2*N+i] = tan(t/2);
  469. //dX[0*N+i] = 0;
  470. //dX[1*N+i] = 0;
  471. //dX[2*N+i] = 1/(cos(t/2)*cos(t/2)+1e-3)/2;
  472. }
  473. { // B <-- lambda Q + Curl(Q)
  474. sctl::Long Nt = Xt.Dim() / COORD_DIM;
  475. B.ReInit(COORD_DIM * ker_potn.Dim(1) * Nt);
  476. B = 0;
  477. sctl::Vector<Real> U(ker_potn.Dim(1) * Nt);
  478. sctl::Vector<Real> gradU(ker_grad.Dim(1) * Nt);
  479. sctl::Vector<Real> J(ker_potn.Dim(0) * N);
  480. for (sctl::Integer k = 0; k < COORD_DIM; k++) {
  481. J = 0;
  482. U = 0;
  483. gradU = 0;
  484. for (sctl::Long i = 0; i < N; i++) J[i] = dX[k * N + i] / N;
  485. ker_potn(X, Xn, J, Xt, U);
  486. ker_grad(X, Xn, J, Xt, gradU);
  487. sctl::Integer k1 = (k + 1) % COORD_DIM;
  488. sctl::Integer k2 = (k + 2) % COORD_DIM;
  489. for (sctl::Long i = 0; i < 2 * Nt; i++) {
  490. B[k * 2 * Nt + i] += lambda * U[i];
  491. B[k1 * 2 * Nt + i] += gradU[k2 * 2 * Nt + i];
  492. B[k2 * 2 * Nt + i] -= gradU[k1 * 2 * Nt + i];
  493. }
  494. }
  495. }
  496. };
  497. for (sctl::Long k = 0; k < Svec.Dim(); k++) {
  498. sctl::Vector<Real> B_;
  499. ref_sol(B_, Svec[k].Coord());
  500. B0 = append_vec(B0, B_);
  501. }
  502. // TODO: Check normal-flux = 0
  503. sctl::Profile::Tic("TaylorConv", &comm);
  504. { // Compute BI solution
  505. sctl::Long Nsurf = Svec.Dim();
  506. if (Nsurf != 1 && Nsurf != 2) return;
  507. sctl::Vector<sctl::Long> SurfDim(Nsurf), SurfDsp(Nsurf);
  508. for (sctl::Long i = 0; i < Nsurf; i++) { // Set SurfDim, SurfDsp
  509. SurfDim[i] = Svec[i].NTor() * Svec[i].NPol();
  510. if (i) SurfDsp[i] = SurfDsp[i-1] + SurfDim[i-1];
  511. else SurfDsp[i] = 0;
  512. }
  513. sctl::Vector<sctl::Vector<Real>> B_taylor;
  514. { // Set B_taylor
  515. sctl::Vector<sctl::Vector<Real>> B, m, sigma;
  516. ComputeHelper(B, m, sigma, lambda, Svec, comm, gmres_tol, gmres_iter);
  517. auto append_imag_part = [&SurfDim,&SurfDsp] (sctl::Vector<Real>& w, const sctl::Vector<Real>& v) {
  518. sctl::Long Nsurf = SurfDim.Dim();
  519. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  520. sctl::Long N = SurfDsp[Nsurf-1]+SurfDim[Nsurf-1];
  521. sctl::Long dof = v.Dim() / N;
  522. SCTL_ASSERT(v.Dim() == N * dof);
  523. if (w.Dim() != N * dof) w.ReInit(dof * 2 * N);
  524. for (sctl::Long i = 0; i < Nsurf; i++) {
  525. for (sctl::Long k = 0; k < dof; k++) {
  526. sctl::Long offset = dof*SurfDsp[i];
  527. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  528. w[2*offset + (k*2+0)*SurfDim[i] + j] = v[offset + k*SurfDim[i] + j];
  529. w[2*offset + (k*2+1)*SurfDim[i] + j] = 0;
  530. }
  531. }
  532. }
  533. };
  534. B_taylor.ReInit(B.Dim());
  535. for (sctl::Long i = 0; i < B.Dim(); i++) append_imag_part(B_taylor[i], B[i]);
  536. }
  537. sctl::Vector<Real> SurfArea(Nsurf); // TODO: remove
  538. sctl::Long OuterSurfIdx = 0, InnerSurfIdx = 0;
  539. sctl::Vector<sctl::Vector<Real>> dX(Nsurf), d2X(Nsurf), Xn(Nsurf), Xa(Nsurf);
  540. for (sctl::Long i = 0; i < Nsurf; i++) { // Set dX, Xn, Xa
  541. const auto& S = Svec[i];
  542. sctl::Long Nt = S.NTor();
  543. sctl::Long Np = S.NPol();
  544. SurfaceOp<Real> surf_op(comm, Nt, Np);
  545. surf_op.Grad2D(dX[i], S.Coord());
  546. surf_op.Grad2D(d2X[i], dX[i]);
  547. surf_op.SurfNormalAreaElem(&Xn[i], &Xa[i], dX[i], &S.Coord());
  548. SurfArea[i] = 0;
  549. for (const auto& da : Xa[i]) SurfArea[i] += da;
  550. }
  551. for (sctl::Long i = 0; i < Nsurf; i++) { // TODO: this is not reliable, use the normal direction to do this
  552. if (SurfArea[i] < SurfArea[InnerSurfIdx]) InnerSurfIdx = i;
  553. if (SurfArea[i] > SurfArea[OuterSurfIdx]) OuterSurfIdx = i;
  554. }
  555. for (sctl::Long i = 0; i < Nsurf; i++) { // Set normal to outer-normal
  556. Real scal = 0;
  557. if (i == InnerSurfIdx) scal = -1;
  558. if (i == OuterSurfIdx) scal = 1;
  559. Xn[i] *= scal;
  560. }
  561. sctl::Profile::Tic("Setup", &comm);
  562. Helmholtz3D<Real> helm(lambda);
  563. HelmholtzDiff3D<Real> helm_diff(lambda);
  564. const auto& ker_potn = helm.FxU();
  565. const auto& ker_grad = helm.FxdU();
  566. const auto& ker_grad_diff = helm_diff.FxdU();
  567. BoundaryIntegralOp<Real,2,6,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_grad_diff(comm);
  568. BoundaryIntegralOp<Real,2,6,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_grad(comm);
  569. BoundaryIntegralOp<Real,2,2,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_potn(comm);
  570. BI_grad_diff.SetupSingular(Svec, ker_grad_diff);
  571. BI_grad.SetupSingular(Svec, ker_grad);
  572. BI_potn.SetupSingular(Svec, ker_potn);
  573. sctl::Profile::Toc();
  574. auto Compute_m = [lambda,&Svec,&SurfDim,&SurfDsp,&dX,&d2X,&Xn,&comm](sctl::Vector<Real>& m, const sctl::Vector<Real>& sigma, Real gmres_tol, sctl::Long gmres_iter) { // m <-- lambda ( i Grad(invLap(sigma)) - Grad(invLap(sigma)) x n )
  575. sctl::Long Nsurf = SurfDim.Dim();
  576. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  577. if (m.Dim() != COORD_DIM * 2 * N) m.ReInit(COORD_DIM * 2 * N);
  578. if (!sigma.Dim() || lambda == 0) { // m = 0
  579. m = 0;
  580. } else {
  581. for (sctl::Long i = 0; i < Nsurf; i++) {
  582. const sctl::Vector<Real> sigma_(2 * SurfDim[i], (sctl::Iterator<Real>)sigma.begin() + 2 * SurfDsp[i], false);
  583. sctl::Vector<Real> m_(COORD_DIM * 2 * SurfDim[i], m.begin() + COORD_DIM * 2 * SurfDsp[i], false);
  584. const auto& S = Svec[i];
  585. sctl::Long Nt = S.NTor();
  586. sctl::Long Np = S.NPol();
  587. sctl::Long N= Nt * Np;
  588. SurfaceOp<Real> surf_op(comm, Nt, Np);
  589. sctl::StaticArray<sctl::Vector<Real>, 2> GradInvLapSigma;
  590. for (sctl::Long k = 0; k < 2; k++) { // Set GradInvLapSigma <-- Grad(invLap(sigma))
  591. const sctl::Vector<Real> sigma__(N, (sctl::Iterator<Real>)sigma_.begin() + k * N, false);
  592. if (max_norm(sigma__) > 0) {
  593. surf_op.GradInvSurfLap(GradInvLapSigma[k], dX[i], d2X[i], sigma__, gmres_tol, gmres_iter, 1.5);
  594. } else {
  595. GradInvLapSigma[k].ReInit(COORD_DIM * N);
  596. GradInvLapSigma[k].SetZero();
  597. }
  598. }
  599. for (sctl::Long j = 0; j < N; j++) { // m <-- lambda ( i GradInvLapSigma - n x GradInvLapSigma )
  600. sctl::StaticArray<Real, COORD_DIM> Xn_, V0_, V1_, nxV0_, nxV1_;
  601. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  602. Xn_[k] = Xn[i][k * N + j];
  603. V0_[k] = GradInvLapSigma[0][k * N + j];
  604. V1_[k] = GradInvLapSigma[1][k * N + j];
  605. }
  606. nxV0_[0] = Xn_[1] * V0_[2] - Xn_[2] * V0_[1];
  607. nxV0_[1] = Xn_[2] * V0_[0] - Xn_[0] * V0_[2];
  608. nxV0_[2] = Xn_[0] * V0_[1] - Xn_[1] * V0_[0];
  609. nxV1_[0] = Xn_[1] * V1_[2] - Xn_[2] * V1_[1];
  610. nxV1_[1] = Xn_[2] * V1_[0] - Xn_[0] * V1_[2];
  611. nxV1_[2] = Xn_[0] * V1_[1] - Xn_[1] * V1_[0];
  612. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  613. m_[(k*2+0) * N + j] = lambda * (-V1_[k] - nxV0_[k]);
  614. m_[(k*2+1) * N + j] = lambda * ( V0_[k] - nxV1_[k]);
  615. }
  616. }
  617. }
  618. }
  619. if (1) {
  620. auto extract_comp = [&SurfDim,&SurfDsp,Nsurf,N](const sctl::Vector<Real>& in, sctl::Long surf_id, sctl::Long comp_id) {
  621. sctl::Long dof = in.Dim() / N;
  622. SCTL_ASSERT(in.Dim() == N * dof);
  623. sctl::Vector<Real> out(SurfDim[surf_id]);
  624. for (sctl::Long i = 0; i < SurfDim[surf_id]; i++) {
  625. out[i] = in[dof * SurfDsp[surf_id] + comp_id * SurfDim[surf_id] + i];
  626. }
  627. return out;
  628. };
  629. auto concat_vec = [](const sctl::Vector<Real>& x, const sctl::Vector<Real>& y) {
  630. sctl::Vector<Real> out;
  631. for (const auto& a : x) out.PushBack(a);
  632. for (const auto& a : y) out.PushBack(a);
  633. return out;
  634. };
  635. { // Print error <-- | SurfDiv(m) - i lambda sigma |_inf
  636. Real err = 0;
  637. for (sctl::Long i = 0; i < Nsurf; i++) {
  638. const auto& S = Svec[i];
  639. sctl::Vector<Real> m_real, m_imag;
  640. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  641. m_real = concat_vec(m_real, extract_comp(m, i, 2*k+0));
  642. m_imag = concat_vec(m_imag, extract_comp(m, i, 2*k+1));
  643. }
  644. sctl::Vector<Real> Divm_real, Divm_imag;
  645. SurfaceOp<Real> surf_op(comm, S.NTor(), S.NPol());
  646. surf_op.SurfDiv(Divm_real, dX[i], m_real);
  647. surf_op.SurfDiv(Divm_imag, dX[i], m_imag);
  648. sctl::Vector<Real> sigma_real, sigma_imag;
  649. if (sigma.Dim()) {
  650. sigma_real = extract_comp(sigma, i, 0);
  651. sigma_imag = extract_comp(sigma, i, 1);
  652. } else {
  653. sigma_real = Divm_real * 0;
  654. sigma_imag = Divm_imag * 0;
  655. }
  656. err = std::max(err, max_norm(Divm_real + sigma_imag * lambda));
  657. err = std::max(err, max_norm(Divm_imag - sigma_real * lambda));
  658. }
  659. std::cout<<"Error : | SurfDiv(m) - i lambda sigma |_inf = "<<err<<"; | m | = "<<max_norm(m)<<"; | lambda sigma | = "<<lambda * max_norm(sigma)<<'\n';
  660. }
  661. { // Print error <-- n x m + i m
  662. Real err = 0;
  663. for (sctl::Long i = 0; i < Nsurf; i++) {
  664. sctl::Vector<Real> m_real, m_imag;
  665. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  666. m_real = concat_vec(m_real, extract_comp(m, i, 2*k+0));
  667. m_imag = concat_vec(m_imag, extract_comp(m, i, 2*k+1));
  668. }
  669. auto cross_prod = [](const sctl::Vector<Real>& x, const sctl::Vector<Real>& y) {
  670. sctl::Long N = x.Dim() / COORD_DIM;
  671. sctl::Vector<Real> z(N * COORD_DIM);
  672. SCTL_ASSERT(x.Dim() == N * COORD_DIM);
  673. SCTL_ASSERT(y.Dim() == N * COORD_DIM);
  674. for (sctl::Long i = 0; i < N; i++) {
  675. sctl::StaticArray<Real, COORD_DIM> x_, y_, z_;
  676. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  677. x_[k] = x[k * N + i];
  678. y_[k] = y[k * N + i];
  679. }
  680. z_[0] = x_[1] * y_[2] - x_[2] * y_[1];
  681. z_[1] = x_[2] * y_[0] - x_[0] * y_[2];
  682. z_[2] = x_[0] * y_[1] - x_[1] * y_[0];
  683. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  684. z[k * N + i] = z_[k];
  685. }
  686. }
  687. return z;
  688. };
  689. sctl::Vector<Real> nxm_real = cross_prod(Xn[i], m_real);
  690. sctl::Vector<Real> nxm_imag = cross_prod(Xn[i], m_imag);
  691. err = std::max(err, max_norm(nxm_real - m_imag));
  692. err = std::max(err, max_norm(nxm_imag + m_real));
  693. }
  694. std::cout<<"Error : | n x m + i m |_inf = "<<err<<'\n';
  695. }
  696. }
  697. };
  698. auto Compute_B = [lambda,&SurfDim,&SurfDsp,&Xn,&BI_grad_diff,&BI_grad,&BI_potn,&ker_grad_diff,&ker_grad,&ker_potn,&comm] (sctl::Vector<Real>* B, sctl::Vector<Real>* B_flux, const sctl::Vector<Real>& sigma, const sctl::Vector<Real>& m0, const sctl::Vector<Real>& mH) {
  699. sctl::Long Nsurf = SurfDim.Dim();
  700. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  701. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  702. sctl::Vector<Real> m;
  703. if (m0.Dim() && mH.Dim()) {
  704. SCTL_ASSERT(m0.Dim() == mH.Dim());
  705. m = m0 + mH;
  706. } else if (m0.Dim()) {
  707. m = m0;
  708. } else if (mH.Dim()) {
  709. m = mH;
  710. }
  711. sctl::Vector<Real> Grad_v, iQ, iCurlQ, iCurlQ_m0, iCurlQ_mH;
  712. if (B && sigma.Dim()) { // Compute Grad_v
  713. sctl::Profile::Tic("Compute_Grad_v", &comm);
  714. Compute_Grad_v(Grad_v, sigma, BI_grad, ker_grad);
  715. sctl::Profile::Toc();
  716. }
  717. if (m.Dim()) { // Compute iQ
  718. sctl::Profile::Tic("Compute_iQ", &comm);
  719. Compute_iQ(iQ, m, SurfDim, SurfDsp, BI_potn, ker_potn, lambda);
  720. sctl::Profile::Toc();
  721. }
  722. if (B && m.Dim()) { // Compute iCurlQ
  723. sctl::Profile::Tic("Compute_iCurlQ", &comm);
  724. Compute_iCurlQ(iCurlQ, m, SurfDim, SurfDsp, BI_grad, ker_grad);
  725. sctl::Profile::Toc();
  726. }
  727. if (B_flux) { // Compute iCurlQ_m0, iCurlQ_mH
  728. sctl::Profile::Tic("Compute_iCurlQ_", &comm);
  729. if (m0.Dim()) Compute_iCurlQ(iCurlQ_m0, m0, SurfDim, SurfDsp, BI_grad , ker_grad );
  730. if (mH.Dim()) Compute_iCurlQ(iCurlQ_mH, mH, SurfDim, SurfDsp, BI_grad_diff, ker_grad_diff);
  731. sctl::Profile::Toc();
  732. }
  733. if (B_flux) { // B_flux <-- iQ*lambda + iCurlQ_mH + iCurlQ_m0 + 0.5*m0
  734. (*B_flux).ReInit(COORD_DIM * 2 * N);
  735. (*B_flux) = 0;
  736. if (m .Dim()) (*B_flux) += iQ*lambda;
  737. if (mH.Dim()) (*B_flux) += iCurlQ_mH;
  738. if (m0.Dim()) (*B_flux) += iCurlQ_m0 + m0*(0.5);
  739. }
  740. if (B) { // B <-- -0.5*sigma_Xn - Grad_v + iQ*lambda + iCurlQ + 0.5*m
  741. (*B).ReInit(COORD_DIM * 2 * N);
  742. (*B) = 0;
  743. if (m.Dim()) (*B) += iQ*lambda + iCurlQ + m*(0.5);
  744. if (sigma.Dim()) { // B <-- B - 0.5*sigma_Xn - Grad_v
  745. sctl::Vector<Real> sigma_Xn(COORD_DIM * 2 * N);
  746. for (sctl::Long i = 0; i < Nsurf; i++) {
  747. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  748. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  749. sigma_Xn[COORD_DIM * 2 * SurfDsp[i] + (k*2+0) * SurfDim[i] + j] = Xn[i][k * SurfDim[i] + j] * sigma[2 * SurfDsp[i] + 0 * SurfDim[i] + j];
  750. sigma_Xn[COORD_DIM * 2 * SurfDsp[i] + (k*2+1) * SurfDim[i] + j] = Xn[i][k * SurfDim[i] + j] * sigma[2 * SurfDsp[i] + 1 * SurfDim[i] + j];
  751. }
  752. }
  753. }
  754. (*B) += sigma_Xn*(-0.5) - Grad_v;
  755. }
  756. }
  757. };
  758. auto Compute_BdotXn = [&SurfDim,&SurfDsp,&Xn](sctl::Vector<Real>& BdotXn, const sctl::Vector<Real>& B) {
  759. sctl::Long Nsurf = SurfDim.Dim();
  760. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  761. sctl::Long N = B.Dim() / (COORD_DIM * 2);
  762. SCTL_ASSERT(B.Dim() == COORD_DIM * 2 * N);
  763. if (BdotXn.Dim() != 2 * N) BdotXn.ReInit(2 * N);
  764. for (sctl::Long i = 0; i < Nsurf; i++) {
  765. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  766. Real B0dotXn = 0, B1dotXn = 0;
  767. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  768. Real Xn_ = Xn[i][k * SurfDim[i] + j];
  769. Real B0 = B[COORD_DIM * 2 * SurfDsp[i] + (k*2+0) * SurfDim[i] + j];
  770. Real B1 = B[COORD_DIM * 2 * SurfDsp[i] + (k*2+1) * SurfDim[i] + j];
  771. B0dotXn += B0 * Xn_;
  772. B1dotXn += B1 * Xn_;
  773. }
  774. BdotXn[2 * SurfDsp[i] + 0 * SurfDim[i] + j] = B0dotXn;
  775. BdotXn[2 * SurfDsp[i] + 1 * SurfDim[i] + j] = B1dotXn;
  776. }
  777. }
  778. };
  779. auto solve_taylor = [lambda,LB_tol,&comm,&Compute_m,&Compute_B,&Compute_BdotXn] (sctl::Vector<Real>& sigma, const sctl::Vector<Real>& rhs, Real gmres_tol, sctl::Long gmres_iter) {
  780. sctl::Profile::Tic("Solve", &comm);
  781. sctl::ParallelSolver<Real> solver(comm, true);
  782. typename sctl::ParallelSolver<Real>::ParallelOp fn = [lambda,LB_tol,&comm,&Compute_m,&Compute_B,&Compute_BdotXn,&gmres_tol,&gmres_iter](sctl::Vector<Real>* BdotXn, const sctl::Vector<Real>& sigma) {
  783. SCTL_ASSERT(BdotXn);
  784. sctl::Vector<Real> m, B;
  785. sctl::Profile::Tic("Compute_B", &comm);
  786. Compute_m(m, sigma, gmres_tol / lambda * LB_tol, gmres_iter);
  787. Compute_B(&B, nullptr, sigma, m, sctl::Vector<Real>());
  788. Compute_BdotXn(*BdotXn, B);
  789. { // Project to space of mean-zero functions : BdotXn <-- P BdotXn
  790. // TODO
  791. }
  792. sctl::Profile::Toc();
  793. };
  794. solver(&sigma, fn, rhs, gmres_tol, gmres_iter);
  795. sctl::Profile::Toc();
  796. };
  797. sctl::Vector<Real> B;
  798. { // Set B <-- B0 - B_sigma
  799. sctl::Vector<Real> rhs, sigma, m;
  800. Compute_BdotXn(rhs, B0);
  801. solve_taylor(sigma, rhs*(-1), gmres_tol, gmres_iter);
  802. Compute_m(m, sigma, gmres_tol / lambda * LB_tol, gmres_iter);
  803. Compute_B(&B, nullptr, sigma, m, sctl::Vector<Real>());
  804. B += B0;
  805. }
  806. sctl::Vector<Real> B_res;
  807. sctl::Profile::Tic("CompResid", &comm);
  808. { // Set B_res <-- B - B_taylor * x
  809. auto complex_vec_scal_prod = [&SurfDim,&SurfDsp] (sctl::Vector<Real>& v, sctl::Complex<Real> c) {
  810. sctl::Long Nsurf = SurfDim.Dim();
  811. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  812. sctl::Long N = SurfDsp[Nsurf-1]+SurfDim[Nsurf-1];
  813. sctl::Long dof = v.Dim() / (N * 2);
  814. SCTL_ASSERT(v.Dim() == N * dof * 2);
  815. for (sctl::Long i = 0; i < Nsurf; i++) {
  816. for (sctl::Long k = 0; k < dof; k++) {
  817. sctl::Long offset = SurfDsp[i]*dof*2 + k*2*SurfDim[i];
  818. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  819. Real v0 = v[offset + 0*SurfDim[i] + j];
  820. Real v1 = v[offset + 1*SurfDim[i] + j];
  821. Real cv0 = v0 * c.real - v1 * c.imag;
  822. Real cv1 = v0 * c.imag + v1 * c.real;
  823. v[offset + 0*SurfDim[i] + j] = cv0;
  824. v[offset + 1*SurfDim[i] + j] = cv1;
  825. }
  826. }
  827. }
  828. };
  829. auto complex_vec_dot_prod = [&SurfDim,&SurfDsp] (const sctl::Vector<Real>& v0, const sctl::Vector<Real>& v1) {
  830. sctl::Long Nsurf = SurfDim.Dim();
  831. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  832. sctl::Long N = SurfDsp[Nsurf-1]+SurfDim[Nsurf-1];
  833. sctl::Long dof = v0.Dim() / (N * 2);
  834. SCTL_ASSERT(v0.Dim() == N * dof * 2);
  835. SCTL_ASSERT(v1.Dim() == N * dof * 2);
  836. sctl::Complex<Real> v1dotv2(0,0);
  837. for (sctl::Long i = 0; i < Nsurf; i++) {
  838. for (sctl::Long k = 0; k < dof; k++) {
  839. sctl::Long offset = SurfDsp[i]*dof*2 + k*2*SurfDim[i];
  840. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  841. sctl::Complex<Real> c0(v0[offset + 0*SurfDim[i] + j], v0[offset + 1*SurfDim[i] + j]);
  842. sctl::Complex<Real> c1(v1[offset + 0*SurfDim[i] + j], v1[offset + 1*SurfDim[i] + j]);
  843. v1dotv2 += c0 * c1;
  844. }
  845. }
  846. }
  847. return v1dotv2;
  848. };
  849. sctl::Matrix<sctl::Complex<Real>> b(B_taylor.Dim(), 1);
  850. sctl::Matrix<sctl::Complex<Real>> M(B_taylor.Dim(), B_taylor.Dim());
  851. for (sctl::Long i = 0; i < B_taylor.Dim(); i++) { // Set b, M
  852. b[i][0] = complex_vec_dot_prod(B,B_taylor[i]);
  853. for (sctl::Long j = 0; j < B_taylor.Dim(); j++) {
  854. M[i][j] = complex_vec_dot_prod(B_taylor[i],B_taylor[j]);
  855. }
  856. }
  857. sctl::Matrix<sctl::Complex<Real>> Minv(B_taylor.Dim(), B_taylor.Dim());
  858. if (M.Dim(0) == 1 && M.Dim(1) == 1) { // Set Minv <-- inv(M)
  859. Minv[0][0] = 1 / M[0][0];
  860. } else if (M.Dim(0) == 2 && M.Dim(1) == 2) {
  861. sctl::Complex<Real> oodet = 1 / (M[0][0] * M[1][1] - M[0][1] * M[1][0]);
  862. Minv[0][0] = M[1][1] * oodet;
  863. Minv[0][1] = -M[0][1] * oodet;
  864. Minv[1][0] = -M[1][0] * oodet;
  865. Minv[1][1] = M[0][0] * oodet;
  866. } else {
  867. SCTL_ASSERT(false);
  868. }
  869. B_res = B;
  870. auto x = Minv * b;
  871. for (sctl::Long i = 0; i < B_taylor.Dim(); i++) {
  872. complex_vec_scal_prod(B_taylor[i], x[i][0]);
  873. B_res -= B_taylor[i];
  874. }
  875. }
  876. sctl::Profile::Toc();
  877. std::cout<<"Error: "<<max_norm(B_res)<<" / "<<max_norm(B0)<<'\n';
  878. WriteVTK("B0", Svec, B0);
  879. WriteVTK("B1", Svec, B);
  880. WriteVTK("B2", Svec, B_res);
  881. }
  882. sctl::Profile::Toc();
  883. }
  884. private:
  885. static Real max_norm(const sctl::Vector<Real>& x) {
  886. Real err = 0;
  887. for (const auto& a : x) err = std::max(err, sctl::fabs<Real>(a));
  888. return err;
  889. }
  890. static void ComputeFarField(sctl::Vector<Real>& Breal, const sctl::Vector<Real>& Xt, const sctl::Vector<sctl::Vector<Real>>& Xsrc, const sctl::Vector<sctl::Vector<Real>>& Xn_src, const sctl::Vector<sctl::Vector<Real>>& sigma, const sctl::Vector<sctl::Vector<Real>>& m, Real lambda) {
  891. sctl::Long Nsurf = Xsrc.Dim();
  892. Helmholtz3D<Real> helm(lambda);
  893. const auto& ker_potn = helm.FxU();
  894. const auto& ker_grad = helm.FxdU();
  895. auto Compute_Grad_v = [&Xt,&Xsrc,&Xn_src,&sigma,&ker_grad,Nsurf](sctl::Vector<Real>& Grad_v) { // grad_v <-- Grad(g[sigma])
  896. sctl::Long Nt = Xt.Dim() / COORD_DIM;
  897. SCTL_ASSERT(Xt.Dim() == Nt * COORD_DIM);
  898. if (Grad_v.Dim() != COORD_DIM * 2 * Nt) Grad_v.ReInit(COORD_DIM * 2 * Nt);
  899. Grad_v = 0;
  900. for (sctl::Long i = 0; i < Nsurf; i++) {
  901. ker_grad(Xsrc[i], Xn_src[i], sigma[i], Xt, Grad_v);
  902. }
  903. };
  904. auto Compute_iQ = [&Xt,&Xsrc,&Xn_src,&m,&ker_potn,Nsurf](sctl::Vector<Real>& iQ) { // iQ <-- g[im]
  905. sctl::Long Nt = Xt.Dim() / COORD_DIM;
  906. SCTL_ASSERT(Xt.Dim() == Nt * COORD_DIM);
  907. if (iQ.Dim() != COORD_DIM * 2 * Nt) iQ.ReInit(COORD_DIM * 2 * Nt);
  908. iQ = 0;
  909. for (sctl::Long i = 0; i < Nsurf; i++) {
  910. sctl::Long N = Xsrc[i].Dim() / COORD_DIM;
  911. sctl::Vector<Real> iQ_(2 * Nt), im_(2 * N);
  912. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  913. for (sctl::Long j = 0; j < N; j++) {
  914. im_[0 * N + j] = -m[i][(k*2+1) * N + j];
  915. im_[1 * N + j] = m[i][(k*2+0) * N + j];
  916. }
  917. iQ_ = 0;
  918. ker_potn(Xsrc[i], Xn_src[i], im_, Xt, iQ_);
  919. for (sctl::Long j = 0; j < Nt; j++) {
  920. iQ[(k*2+0) * Nt + j] += iQ_[0 * Nt + j];
  921. iQ[(k*2+1) * Nt + j] += iQ_[1 * Nt + j];
  922. }
  923. }
  924. }
  925. };
  926. auto Compute_iCurlQ = [&Xt,&Xsrc,&Xn_src,&m,&ker_grad,Nsurf](sctl::Vector<Real>& iCurlQ) { // iCurlQ <-- Curl(g[im])
  927. sctl::Long Nt = Xt.Dim() / COORD_DIM;
  928. SCTL_ASSERT(Xt.Dim() == Nt * COORD_DIM);
  929. if (iCurlQ.Dim() != COORD_DIM * 2 * Nt) iCurlQ.ReInit(COORD_DIM * 2 * Nt);
  930. iCurlQ = 0;
  931. for (sctl::Long i = 0; i < Nsurf; i++) {
  932. sctl::Long N = Xsrc[i].Dim() / COORD_DIM;
  933. sctl::Vector<Real> iGradQ_(2 * COORD_DIM * Nt), im_(2 * N);
  934. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  935. for (sctl::Long j = 0; j < N; j++) {
  936. im_[0 * N + j] = -m[i][(k*2+1) * N + j];
  937. im_[1 * N + j] = m[i][(k*2+0) * N + j];
  938. }
  939. iGradQ_ = 0;
  940. ker_grad(Xsrc[i], Xn_src[i], im_, Xt, iGradQ_);
  941. sctl::Long k0 = (k + 2) % COORD_DIM;
  942. sctl::Long k1 = (k + 1) % COORD_DIM;
  943. for (sctl::Long j = 0; j < Nt; j++) {
  944. iCurlQ[(k1*2+0) * Nt + j] += iGradQ_[(k0*2+0) * Nt + j];
  945. iCurlQ[(k1*2+1) * Nt + j] += iGradQ_[(k0*2+1) * Nt + j];
  946. iCurlQ[(k0*2+0) * Nt + j] -= iGradQ_[(k1*2+0) * Nt + j];
  947. iCurlQ[(k0*2+1) * Nt + j] -= iGradQ_[(k1*2+1) * Nt + j];
  948. }
  949. }
  950. }
  951. };
  952. sctl::Long N = Xt.Dim() / COORD_DIM;
  953. SCTL_ASSERT(Xt.Dim() == COORD_DIM * N);
  954. sctl::Vector<Real> Grad_v, iQ, iCurlQ;
  955. if (sigma.Dim()) { // Compute Grad_v
  956. Compute_Grad_v(Grad_v);
  957. }
  958. if (m.Dim()) { // Compute iQ
  959. Compute_iQ(iQ);
  960. }
  961. if (m.Dim()) { // Compute iCurlQ
  962. Compute_iCurlQ(iCurlQ);
  963. }
  964. sctl::Vector<Real> B(COORD_DIM * 2 * N);
  965. { // B <-- - Grad_v + iQ*lambda + iCurlQ
  966. B = 0;
  967. if (m.Dim()) B += iQ*lambda + iCurlQ;
  968. if (sigma.Dim()) B -= Grad_v;
  969. }
  970. { // Breal <-- real(B)
  971. sctl::Long N = B.Dim() / (2 * COORD_DIM);
  972. if (Breal.Dim() != COORD_DIM * N) Breal.ReInit(COORD_DIM * N);
  973. for (sctl::Long i = 0; i < N; i++) {
  974. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  975. Breal[k * N + i] = B[k * 2 * N + i];
  976. }
  977. }
  978. }
  979. }
  980. static void Compute_mH(sctl::Vector<Real>& mH, const Surface<Real>& S, const sctl::Vector<Real>& dX, const sctl::Vector<Real>& d2X, const sctl::Vector<Real>& Xn, const sctl::Comm& comm, Real tol, sctl::Long max_iter) {
  981. sctl::Long Nt = S.NTor();
  982. sctl::Long Np = S.NPol();
  983. sctl::Long N= Nt * Np;
  984. sctl::Vector<Real> V(COORD_DIM * N);
  985. #pragma omp parallel for schedule(static)
  986. for (sctl::Long i = 0; i < N; i++) { // Set V
  987. for (sctl::Long k =0; k < COORD_DIM; k++) {
  988. V[k * N + i] = dX[(k*2+0) * N + i];
  989. }
  990. }
  991. sctl::Vector<Real> Vn, Vd, Vc, Vh;
  992. SurfaceOp<Real> surf_op(comm, Nt, Np);
  993. surf_op.HodgeDecomp(Vn, Vd, Vc, Vh, V, dX, d2X, Xn, tol, max_iter);
  994. if (mH.Dim() != COORD_DIM * 2 * N) mH.ReInit(COORD_DIM * 2 * N);
  995. #pragma omp parallel for schedule(static)
  996. for (sctl::Long i = 0; i < N; i++) { // Set mH
  997. sctl::StaticArray<Real, COORD_DIM> Xn_, Vh_, nxVh_;
  998. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  999. Xn_[k] = Xn[k * N + i];
  1000. Vh_[k] = Vh[k * N + i];
  1001. }
  1002. nxVh_[0] = Xn_[1] * Vh_[2] - Xn_[2] * Vh_[1];
  1003. nxVh_[1] = Xn_[2] * Vh_[0] - Xn_[0] * Vh_[2];
  1004. nxVh_[2] = Xn_[0] * Vh_[1] - Xn_[1] * Vh_[0];
  1005. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1006. mH[(k*2+0) * N + i] = Vh_[k];
  1007. mH[(k*2+1) * N + i] = nxVh_[k];
  1008. }
  1009. }
  1010. }
  1011. static void Compute_Grad_v(sctl::Vector<Real>& Grad_v, const sctl::Vector<Real>& sigma, const BoundaryIntegralOp<Real,2,6,UPSAMPLE,PATCH_DIM0,RAD_DIM>& BI_grad, const KernelFunction<Real,COORD_DIM,2,COORD_DIM*2>& ker_grad) { // grad_v <-- Grad(g[sigma])
  1012. Grad_v = 0;
  1013. BI_grad(Grad_v, sigma);
  1014. }
  1015. static void Compute_iQ(sctl::Vector<Real>& iQ, const sctl::Vector<Real>& m, const sctl::Vector<sctl::Long>& SurfDim, const sctl::Vector<sctl::Long>& SurfDsp, const BoundaryIntegralOp<Real,2,2,UPSAMPLE,PATCH_DIM0,RAD_DIM>& BI_potn, const KernelFunction<Real,COORD_DIM,2,2>& ker_potn, Real lambda) { // iQ <-- i g[m]
  1016. sctl::Long Nsurf = SurfDim.Dim();
  1017. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  1018. if (iQ.Dim() != COORD_DIM * 2 * N) iQ.ReInit(COORD_DIM * 2 * N);
  1019. SCTL_ASSERT(m.Dim() == COORD_DIM * 2 * N);
  1020. iQ = 0;
  1021. #ifdef USE_QBX
  1022. BI_potn.template HelmholtzQBX<2>(iQ, m, ker_potn, lambda);
  1023. #else
  1024. BI_potn(iQ, m);
  1025. #endif
  1026. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1027. for (sctl::Long i = 0; i < Nsurf; i++) {
  1028. #pragma omp parallel for schedule(static)
  1029. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  1030. Real real_Q = iQ[COORD_DIM * 2 * SurfDsp[i] + (k*2+0) * SurfDim[i] + j];
  1031. Real imag_Q = iQ[COORD_DIM * 2 * SurfDsp[i] + (k*2+1) * SurfDim[i] + j];
  1032. iQ[COORD_DIM * 2 * SurfDsp[i] + (k*2+0) * SurfDim[i] + j] = -imag_Q;
  1033. iQ[COORD_DIM * 2 * SurfDsp[i] + (k*2+1) * SurfDim[i] + j] = real_Q;
  1034. }
  1035. }
  1036. }
  1037. }
  1038. static void Compute_iCurlQ(sctl::Vector<Real>& iCurlQ, const sctl::Vector<Real>& m, const sctl::Vector<sctl::Long>& SurfDim, const sctl::Vector<sctl::Long>& SurfDsp, const BoundaryIntegralOp<Real,2,6,UPSAMPLE,PATCH_DIM0,RAD_DIM>& BI_grad, const KernelFunction<Real,COORD_DIM,2,COORD_DIM*2>& ker_grad) { // iCurlQ <-- i Curl(g[m])
  1039. sctl::Long Nsurf = SurfDim.Dim();
  1040. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  1041. if (iCurlQ.Dim() != COORD_DIM * 2 * N) iCurlQ.ReInit(COORD_DIM * 2 * N);
  1042. SCTL_ASSERT(m.Dim() == COORD_DIM * 2 * N);
  1043. sctl::Vector<Real> GradQ_(COORD_DIM * COORD_DIM * 2 * N);
  1044. GradQ_ = 0;
  1045. BI_grad(GradQ_, m);
  1046. iCurlQ = 0;
  1047. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1048. sctl::Long k0 = (k + 2) % COORD_DIM;
  1049. sctl::Long k1 = (k + 1) % COORD_DIM;
  1050. for (sctl::Long i = 0; i < Nsurf; i++) {
  1051. #pragma omp parallel for schedule(static)
  1052. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  1053. iCurlQ[COORD_DIM * 2 * SurfDsp[i] + (k1*2+0) * SurfDim[i] + j] += -GradQ_[COORD_DIM * COORD_DIM * 2 * SurfDsp[i] + ((k*COORD_DIM+k0)*2+1) * SurfDim[i] + j];
  1054. iCurlQ[COORD_DIM * 2 * SurfDsp[i] + (k1*2+1) * SurfDim[i] + j] += GradQ_[COORD_DIM * COORD_DIM * 2 * SurfDsp[i] + ((k*COORD_DIM+k0)*2+0) * SurfDim[i] + j];
  1055. iCurlQ[COORD_DIM * 2 * SurfDsp[i] + (k0*2+0) * SurfDim[i] + j] -= -GradQ_[COORD_DIM * COORD_DIM * 2 * SurfDsp[i] + ((k*COORD_DIM+k1)*2+1) * SurfDim[i] + j];
  1056. iCurlQ[COORD_DIM * 2 * SurfDsp[i] + (k0*2+1) * SurfDim[i] + j] -= GradQ_[COORD_DIM * COORD_DIM * 2 * SurfDsp[i] + ((k*COORD_DIM+k1)*2+0) * SurfDim[i] + j];
  1057. }
  1058. }
  1059. }
  1060. }
  1061. static void ComputeHelper(sctl::Vector<sctl::Vector<Real>>& B_out, sctl::Vector<sctl::Vector<Real>>& m_out, sctl::Vector<sctl::Vector<Real>>& sigma_out, Real lambda, const sctl::Vector<Surface<Real>>& Svec, const sctl::Comm& comm, Real gmres_tol, sctl::Long gmres_iter, Real LB_tol = 0.1) {
  1062. sctl::Long Nsurf = Svec.Dim();
  1063. if (Nsurf != 1 && Nsurf != 2) return;
  1064. sctl::Vector<sctl::Long> SurfDim(Nsurf), SurfDsp(Nsurf);
  1065. for (sctl::Long i = 0; i < Nsurf; i++) { // Set SurfDim, SurfDsp
  1066. SurfDim[i] = Svec[i].NTor() * Svec[i].NPol();
  1067. if (i) SurfDsp[i] = SurfDsp[i-1] + SurfDim[i-1];
  1068. else SurfDsp[i] = 0;
  1069. }
  1070. sctl::Vector<Real> SurfArea(Nsurf); // TODO: remove
  1071. sctl::Long OuterSurfIdx = 0, InnerSurfIdx = 0;
  1072. sctl::Vector<sctl::Vector<Real>> dX(Nsurf), d2X(Nsurf), Xn(Nsurf), Xa(Nsurf);
  1073. for (sctl::Long i = 0; i < Nsurf; i++) { // Set dX, Xn, Xa
  1074. const auto& S = Svec[i];
  1075. sctl::Long Nt = S.NTor();
  1076. sctl::Long Np = S.NPol();
  1077. SurfaceOp<Real> surf_op(comm, Nt, Np);
  1078. surf_op.Grad2D(dX[i], S.Coord());
  1079. surf_op.Grad2D(d2X[i], dX[i]);
  1080. surf_op.SurfNormalAreaElem(&Xn[i], &Xa[i], dX[i], &S.Coord());
  1081. SurfArea[i] = 0;
  1082. for (const auto& da : Xa[i]) SurfArea[i] += da;
  1083. }
  1084. for (sctl::Long i = 0; i < Nsurf; i++) { // TODO: this is not reliable, use the normal direction to do this
  1085. if (SurfArea[i] < SurfArea[InnerSurfIdx]) InnerSurfIdx = i;
  1086. if (SurfArea[i] > SurfArea[OuterSurfIdx]) OuterSurfIdx = i;
  1087. }
  1088. for (sctl::Long i = 0; i < Nsurf; i++) { // Set normal to outer-normal
  1089. Real scal = 0;
  1090. if (i == InnerSurfIdx) scal = -1;
  1091. if (i == OuterSurfIdx) scal = 1;
  1092. Xn[i] *= scal;
  1093. }
  1094. sctl::Profile::Tic("Setup", &comm);
  1095. Helmholtz3D<Real> helm(lambda);
  1096. HelmholtzDiff3D<Real> helm_diff(lambda);
  1097. const auto& ker_potn = helm.FxU();
  1098. const auto& ker_grad = helm.FxdU();
  1099. const auto& ker_grad_diff = helm_diff.FxdU();
  1100. BoundaryIntegralOp<Real,2,6,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_grad_diff(comm);
  1101. BoundaryIntegralOp<Real,2,6,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_grad(comm);
  1102. BoundaryIntegralOp<Real,2,2,UPSAMPLE,PATCH_DIM0,RAD_DIM> BI_potn(comm);
  1103. BI_grad_diff.SetupSingular(Svec, ker_grad_diff);
  1104. BI_grad.SetupSingular(Svec, ker_grad);
  1105. BI_potn.SetupSingular(Svec, ker_potn);
  1106. sctl::Profile::Toc();
  1107. auto Compute_m = [lambda,&Svec,&SurfDim,&SurfDsp,&dX,&d2X,&Xn,&comm](sctl::Vector<Real>& m, const sctl::Vector<Real>& sigma, Real gmres_tol, sctl::Long gmres_iter) { // m <-- lambda ( i Grad(invLap(sigma)) - Grad(invLap(sigma)) x n )
  1108. sctl::Long Nsurf = SurfDim.Dim();
  1109. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  1110. if (m.Dim() != COORD_DIM * 2 * N) m.ReInit(COORD_DIM * 2 * N);
  1111. if (!sigma.Dim() || lambda == 0) { // m = 0
  1112. m = 0;
  1113. } else {
  1114. for (sctl::Long i = 0; i < Nsurf; i++) {
  1115. const sctl::Vector<Real> sigma_(2 * SurfDim[i], (sctl::Iterator<Real>)sigma.begin() + 2 * SurfDsp[i], false);
  1116. sctl::Vector<Real> m_(COORD_DIM * 2 * SurfDim[i], m.begin() + COORD_DIM * 2 * SurfDsp[i], false);
  1117. const auto& S = Svec[i];
  1118. sctl::Long Nt = S.NTor();
  1119. sctl::Long Np = S.NPol();
  1120. sctl::Long N= Nt * Np;
  1121. SurfaceOp<Real> surf_op(comm, Nt, Np);
  1122. sctl::StaticArray<sctl::Vector<Real>, 2> GradInvLapSigma;
  1123. for (sctl::Long k = 0; k < 2; k++) { // Set GradInvLapSigma <-- Grad(invLap(sigma))
  1124. const sctl::Vector<Real> sigma__(N, (sctl::Iterator<Real>)sigma_.begin() + k * N, false);
  1125. if (max_norm(sigma__) > 0) {
  1126. surf_op.GradInvSurfLap(GradInvLapSigma[k], dX[i], d2X[i], sigma__, gmres_tol, gmres_iter, 1.5);
  1127. } else {
  1128. GradInvLapSigma[k].ReInit(COORD_DIM * N);
  1129. GradInvLapSigma[k].SetZero();
  1130. }
  1131. }
  1132. for (sctl::Long j = 0; j < N; j++) { // m <-- lambda ( i GradInvLapSigma - n x GradInvLapSigma )
  1133. sctl::StaticArray<Real, COORD_DIM> Xn_, V0_, V1_, nxV0_, nxV1_;
  1134. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1135. Xn_[k] = Xn[i][k * N + j];
  1136. V0_[k] = GradInvLapSigma[0][k * N + j];
  1137. V1_[k] = GradInvLapSigma[1][k * N + j];
  1138. }
  1139. nxV0_[0] = Xn_[1] * V0_[2] - Xn_[2] * V0_[1];
  1140. nxV0_[1] = Xn_[2] * V0_[0] - Xn_[0] * V0_[2];
  1141. nxV0_[2] = Xn_[0] * V0_[1] - Xn_[1] * V0_[0];
  1142. nxV1_[0] = Xn_[1] * V1_[2] - Xn_[2] * V1_[1];
  1143. nxV1_[1] = Xn_[2] * V1_[0] - Xn_[0] * V1_[2];
  1144. nxV1_[2] = Xn_[0] * V1_[1] - Xn_[1] * V1_[0];
  1145. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1146. m_[(k*2+0) * N + j] = lambda * (-V1_[k] - nxV0_[k]);
  1147. m_[(k*2+1) * N + j] = lambda * ( V0_[k] - nxV1_[k]);
  1148. }
  1149. }
  1150. }
  1151. }
  1152. if (1) {
  1153. #ifdef BIEST_VERBOSE
  1154. auto extract_comp = [&SurfDim,&SurfDsp,Nsurf,N](const sctl::Vector<Real>& in, sctl::Long surf_id, sctl::Long comp_id) {
  1155. sctl::Long dof = in.Dim() / N;
  1156. SCTL_ASSERT(in.Dim() == N * dof);
  1157. sctl::Vector<Real> out(SurfDim[surf_id]);
  1158. for (sctl::Long i = 0; i < SurfDim[surf_id]; i++) {
  1159. out[i] = in[dof * SurfDsp[surf_id] + comp_id * SurfDim[surf_id] + i];
  1160. }
  1161. return out;
  1162. };
  1163. auto concat_vec = [](const sctl::Vector<Real>& x, const sctl::Vector<Real>& y) {
  1164. sctl::Vector<Real> out;
  1165. for (const auto& a : x) out.PushBack(a);
  1166. for (const auto& a : y) out.PushBack(a);
  1167. return out;
  1168. };
  1169. { // Print error <-- | SurfDiv(m) - i lambda sigma |_inf
  1170. Real err = 0;
  1171. for (sctl::Long i = 0; i < Nsurf; i++) {
  1172. const auto& S = Svec[i];
  1173. sctl::Vector<Real> m_real, m_imag;
  1174. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1175. m_real = concat_vec(m_real, extract_comp(m, i, 2*k+0));
  1176. m_imag = concat_vec(m_imag, extract_comp(m, i, 2*k+1));
  1177. }
  1178. sctl::Vector<Real> Divm_real, Divm_imag;
  1179. SurfaceOp<Real> surf_op(comm, S.NTor(), S.NPol());
  1180. surf_op.SurfDiv(Divm_real, dX[i], m_real);
  1181. surf_op.SurfDiv(Divm_imag, dX[i], m_imag);
  1182. sctl::Vector<Real> sigma_real, sigma_imag;
  1183. if (sigma.Dim()) {
  1184. sigma_real = extract_comp(sigma, i, 0);
  1185. sigma_imag = extract_comp(sigma, i, 1);
  1186. } else {
  1187. sigma_real = Divm_real * 0;
  1188. sigma_imag = Divm_imag * 0;
  1189. }
  1190. err = std::max(err, max_norm(Divm_real + sigma_imag * lambda));
  1191. err = std::max(err, max_norm(Divm_imag - sigma_real * lambda));
  1192. }
  1193. std::cout<<"Error : | SurfDiv(m) - i lambda sigma |_inf = "<<err<<"; | m | = "<<max_norm(m)<<"; | lambda sigma | = "<<lambda * max_norm(sigma)<<'\n';
  1194. }
  1195. { // Print error <-- n x m + i m
  1196. Real err = 0;
  1197. for (sctl::Long i = 0; i < Nsurf; i++) {
  1198. sctl::Vector<Real> m_real, m_imag;
  1199. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1200. m_real = concat_vec(m_real, extract_comp(m, i, 2*k+0));
  1201. m_imag = concat_vec(m_imag, extract_comp(m, i, 2*k+1));
  1202. }
  1203. auto cross_prod = [](const sctl::Vector<Real>& x, const sctl::Vector<Real>& y) {
  1204. sctl::Long N = x.Dim() / COORD_DIM;
  1205. sctl::Vector<Real> z(N * COORD_DIM);
  1206. SCTL_ASSERT(x.Dim() == N * COORD_DIM);
  1207. SCTL_ASSERT(y.Dim() == N * COORD_DIM);
  1208. for (sctl::Long i = 0; i < N; i++) {
  1209. sctl::StaticArray<Real, COORD_DIM> x_, y_, z_;
  1210. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1211. x_[k] = x[k * N + i];
  1212. y_[k] = y[k * N + i];
  1213. }
  1214. z_[0] = x_[1] * y_[2] - x_[2] * y_[1];
  1215. z_[1] = x_[2] * y_[0] - x_[0] * y_[2];
  1216. z_[2] = x_[0] * y_[1] - x_[1] * y_[0];
  1217. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1218. z[k * N + i] = z_[k];
  1219. }
  1220. }
  1221. return z;
  1222. };
  1223. sctl::Vector<Real> nxm_real = cross_prod(Xn[i], m_real);
  1224. sctl::Vector<Real> nxm_imag = cross_prod(Xn[i], m_imag);
  1225. err = std::max(err, max_norm(nxm_real - m_imag));
  1226. err = std::max(err, max_norm(nxm_imag + m_real));
  1227. }
  1228. std::cout<<"Error : | n x m + i m |_inf = "<<err<<'\n';
  1229. }
  1230. #endif
  1231. }
  1232. };
  1233. auto Compute_B = [lambda,&SurfDim,&SurfDsp,&Xn,&BI_grad_diff,&BI_grad,&BI_potn,&ker_grad_diff,&ker_grad,&ker_potn,&comm] (sctl::Vector<Real>* B, sctl::Vector<Real>* B_flux, const sctl::Vector<Real>& sigma, const sctl::Vector<Real>& m0, const sctl::Vector<Real>& mH) {
  1234. sctl::Long Nsurf = SurfDim.Dim();
  1235. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  1236. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  1237. sctl::Vector<Real> m;
  1238. if (m0.Dim() && mH.Dim()) {
  1239. SCTL_ASSERT(m0.Dim() == mH.Dim());
  1240. m = m0 + mH;
  1241. } else if (m0.Dim()) {
  1242. m = m0;
  1243. } else if (mH.Dim()) {
  1244. m = mH;
  1245. }
  1246. sctl::Vector<Real> Grad_v, iQ, iCurlQ, iCurlQ_m0, iCurlQ_mH;
  1247. if (B && sigma.Dim()) { // Compute Grad_v
  1248. sctl::Profile::Tic("Compute_Grad_v", &comm);
  1249. Compute_Grad_v(Grad_v, sigma, BI_grad, ker_grad);
  1250. sctl::Profile::Toc();
  1251. }
  1252. if (m.Dim()) { // Compute iQ
  1253. sctl::Profile::Tic("Compute_iQ", &comm);
  1254. Compute_iQ(iQ, m, SurfDim, SurfDsp, BI_potn, ker_potn, lambda);
  1255. sctl::Profile::Toc();
  1256. }
  1257. if (B && m.Dim()) { // Compute iCurlQ
  1258. sctl::Profile::Tic("Compute_iCurlQ", &comm);
  1259. Compute_iCurlQ(iCurlQ, m, SurfDim, SurfDsp, BI_grad, ker_grad);
  1260. sctl::Profile::Toc();
  1261. }
  1262. if (B_flux) { // Compute iCurlQ_m0, iCurlQ_mH
  1263. sctl::Profile::Tic("Compute_iCurlQ_", &comm);
  1264. if (m0.Dim()) Compute_iCurlQ(iCurlQ_m0, m0, SurfDim, SurfDsp, BI_grad , ker_grad );
  1265. if (mH.Dim()) Compute_iCurlQ(iCurlQ_mH, mH, SurfDim, SurfDsp, BI_grad_diff, ker_grad_diff);
  1266. sctl::Profile::Toc();
  1267. }
  1268. if (B_flux) { // B_flux <-- iQ*lambda + iCurlQ_mH + iCurlQ_m0 + 0.5*m0
  1269. (*B_flux).ReInit(COORD_DIM * 2 * N);
  1270. (*B_flux) = 0;
  1271. if (m .Dim()) (*B_flux) += iQ*lambda;
  1272. if (mH.Dim()) (*B_flux) += iCurlQ_mH;
  1273. if (m0.Dim()) (*B_flux) += iCurlQ_m0 + m0*(0.5);
  1274. }
  1275. if (B) { // B <-- -0.5*sigma_Xn - Grad_v + iQ*lambda + iCurlQ + 0.5*m
  1276. (*B).ReInit(COORD_DIM * 2 * N);
  1277. (*B) = 0;
  1278. if (m.Dim()) (*B) += iQ*lambda + iCurlQ + m*(0.5);
  1279. if (sigma.Dim()) { // B <-- B - 0.5*sigma_Xn - Grad_v
  1280. sctl::Vector<Real> sigma_Xn(COORD_DIM * 2 * N);
  1281. for (sctl::Long i = 0; i < Nsurf; i++) {
  1282. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1283. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  1284. sigma_Xn[COORD_DIM * 2 * SurfDsp[i] + (k*2+0) * SurfDim[i] + j] = Xn[i][k * SurfDim[i] + j] * sigma[2 * SurfDsp[i] + 0 * SurfDim[i] + j];
  1285. sigma_Xn[COORD_DIM * 2 * SurfDsp[i] + (k*2+1) * SurfDim[i] + j] = Xn[i][k * SurfDim[i] + j] * sigma[2 * SurfDsp[i] + 1 * SurfDim[i] + j];
  1286. }
  1287. }
  1288. }
  1289. (*B) += sigma_Xn*(-0.5) - Grad_v;
  1290. }
  1291. }
  1292. };
  1293. auto Compute_BdotXn = [&SurfDim,&SurfDsp,&Xn](sctl::Vector<Real>& BdotXn, const sctl::Vector<Real>& B) {
  1294. sctl::Long Nsurf = SurfDim.Dim();
  1295. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  1296. sctl::Long N = B.Dim() / (COORD_DIM * 2);
  1297. SCTL_ASSERT(B.Dim() == COORD_DIM * 2 * N);
  1298. if (BdotXn.Dim() != 2 * N) BdotXn.ReInit(2 * N);
  1299. for (sctl::Long i = 0; i < Nsurf; i++) {
  1300. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  1301. Real B0dotXn = 0, B1dotXn = 0;
  1302. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1303. Real Xn_ = Xn[i][k * SurfDim[i] + j];
  1304. Real B0 = B[COORD_DIM * 2 * SurfDsp[i] + (k*2+0) * SurfDim[i] + j];
  1305. Real B1 = B[COORD_DIM * 2 * SurfDsp[i] + (k*2+1) * SurfDim[i] + j];
  1306. B0dotXn += B0 * Xn_;
  1307. B1dotXn += B1 * Xn_;
  1308. }
  1309. BdotXn[2 * SurfDsp[i] + 0 * SurfDim[i] + j] = B0dotXn;
  1310. BdotXn[2 * SurfDsp[i] + 1 * SurfDim[i] + j] = B1dotXn;
  1311. }
  1312. }
  1313. };
  1314. auto solve_taylor = [lambda,LB_tol,&comm,&Compute_m,&Compute_B,&Compute_BdotXn] (sctl::Vector<Real>& sigma, const sctl::Vector<Real>& rhs, Real gmres_tol, sctl::Long gmres_iter) {
  1315. sctl::Profile::Tic("Solve", &comm);
  1316. sctl::ParallelSolver<Real> solver(comm, true);
  1317. typename sctl::ParallelSolver<Real>::ParallelOp fn = [lambda,LB_tol,&comm,&Compute_m,&Compute_B,&Compute_BdotXn,&gmres_tol,&gmres_iter](sctl::Vector<Real>* BdotXn, const sctl::Vector<Real>& sigma) {
  1318. SCTL_ASSERT(BdotXn);
  1319. sctl::Vector<Real> m, B;
  1320. sctl::Profile::Tic("Compute_B", &comm);
  1321. Compute_m(m, sigma, gmres_tol / lambda * LB_tol, gmres_iter);
  1322. Compute_B(&B, nullptr, sigma, m, sctl::Vector<Real>());
  1323. Compute_BdotXn(*BdotXn, B);
  1324. { // Project to space of mean-zero functions : BdotXn <-- P BdotXn
  1325. // TODO
  1326. }
  1327. sctl::Profile::Toc();
  1328. };
  1329. solver(&sigma, fn, rhs, gmres_tol, gmres_iter);
  1330. sctl::Profile::Toc();
  1331. };
  1332. sctl::Vector<sctl::Vector<Real>> mH(Nsurf), B0(Nsurf);
  1333. sctl::Profile::Tic("Compute_B0", &comm);
  1334. for (sctl::Long i = 0; i < Nsurf; i++) { // Compute mH, B0
  1335. mH[i].ReInit(COORD_DIM * 2 * (SurfDim[Nsurf-1] + SurfDsp[Nsurf-1])); mH[i] = 0;
  1336. sctl::Vector<Real> mH_(COORD_DIM * 2 * SurfDim[i], mH[i].begin() + COORD_DIM * 2 * SurfDsp[i], false);
  1337. Compute_mH(mH_, Svec[i], dX[i], d2X[i], Xn[i], comm, gmres_tol * LB_tol, gmres_iter);
  1338. Compute_B(&B0[i], nullptr, sctl::Vector<Real>(), sctl::Vector<Real>(), mH[i]*(-1));
  1339. }
  1340. sctl::Profile::Toc();
  1341. sctl::Vector<sctl::Vector<Real>> sigma(Nsurf), m(Nsurf), B(Nsurf), B_flux(Nsurf);
  1342. for (sctl::Long i = 0; i < Nsurf; i++) { // Solve
  1343. sctl::Vector<Real> rhs;
  1344. Compute_BdotXn(rhs, B0[i]);
  1345. solve_taylor(sigma[i], rhs, gmres_tol, gmres_iter);
  1346. Compute_m(m[i], sigma[i], gmres_tol * LB_tol, gmres_iter);
  1347. Compute_B(&B[i], &B_flux[i], sigma[i], m[i], mH[i]);
  1348. m[i] += mH[i];
  1349. }
  1350. sctl::Profile::Tic("CompFlux", &comm);
  1351. { // Compute flux
  1352. auto compute_tor_circ = [&Svec,&SurfDim,&SurfDsp,dX](sctl::Vector<Real>* circ, const sctl::Vector<Real>& A, sctl::Long surf_id) {
  1353. sctl::Long Nsurf = Svec.Dim();
  1354. SCTL_ASSERT(surf_id < Nsurf);
  1355. const auto& S = Svec[surf_id];
  1356. sctl::Long Nt = S.NTor();
  1357. sctl::Long Np = S.NPol();
  1358. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  1359. sctl::Long dof = A.Dim() / (N * COORD_DIM);
  1360. SCTL_ASSERT(A.Dim() == N * COORD_DIM * dof);
  1361. sctl::Long offset = SurfDsp[surf_id] * COORD_DIM * dof;
  1362. sctl::Complex<Real> circ_ = 0;
  1363. sctl::Vector<Real> circ_vec(dof*Np);
  1364. for (sctl::Long d = 0; d < dof; d++) {
  1365. for (sctl::Long p = 0; p < Np; p++) {
  1366. Real integ0 = 0;
  1367. for (sctl::Long t = 0; t < Nt; t++) {
  1368. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1369. Real A0 = A[offset + (k*dof+d)*Nt*Np + t*Np + p];
  1370. Real dX_ = dX[surf_id][(2*k+0)*Nt*Np + t*Np + p];
  1371. integ0 += A0 * dX_;
  1372. }
  1373. }
  1374. circ_vec[d * Np + p] = integ0 / Nt;
  1375. if (!d) circ_.real += integ0 / (Nt*Np);
  1376. else circ_.imag += integ0 / (Nt*Np);
  1377. }
  1378. }
  1379. if (circ) (*circ) = circ_vec;
  1380. for (sctl::Long d = 0; d < dof; d++) {
  1381. for (sctl::Long p = 0; p < Np; p++) {
  1382. if (!d) circ_vec[d * Np + p] -= circ_.real;
  1383. else circ_vec[d * Np + p] -= circ_.imag;
  1384. }
  1385. }
  1386. return circ_;
  1387. };
  1388. auto compute_pol_circ = [&Svec,&SurfDim,&SurfDsp,dX](sctl::Vector<Real>* circ, const sctl::Vector<Real>& A, sctl::Long surf_id) {
  1389. sctl::Long Nsurf = Svec.Dim();
  1390. SCTL_ASSERT(surf_id < Nsurf);
  1391. const auto& S = Svec[surf_id];
  1392. sctl::Long Nt = S.NTor();
  1393. sctl::Long Np = S.NPol();
  1394. sctl::Long N = SurfDim[Nsurf-1] + SurfDsp[Nsurf-1];
  1395. sctl::Long dof = A.Dim() / (N * COORD_DIM);
  1396. SCTL_ASSERT(A.Dim() == N * COORD_DIM * dof);
  1397. sctl::Long offset = SurfDsp[surf_id] * COORD_DIM * dof;
  1398. sctl::Complex<Real> circ_ = 0;
  1399. sctl::Vector<Real> circ_vec(dof*Nt);
  1400. for (sctl::Long d = 0; d < dof; d++) {
  1401. for (sctl::Long t = 0; t < Nt; t++) {
  1402. Real integ0 = 0;
  1403. for (sctl::Long p = 0; p < Np; p++) {
  1404. for (sctl::Long k = 0; k < COORD_DIM; k++) {
  1405. Real A0 = A[offset + (k*dof+d)*Nt*Np + t*Np + p];
  1406. Real dX_ = dX[surf_id][(2*k+1)*Nt*Np + t*Np + p];
  1407. integ0 += A0 * dX_;
  1408. }
  1409. }
  1410. circ_vec[d * Nt + t] = integ0 / Np;
  1411. if (!d) circ_.real += integ0 / (Nt*Np);
  1412. else circ_.imag += integ0 / (Nt*Np);
  1413. }
  1414. }
  1415. if (circ) (*circ) = circ_vec;
  1416. for (sctl::Long d = 0; d < dof; d++) {
  1417. for (sctl::Long t = 0; t < Nt; t++) {
  1418. if (!d) circ_vec[d * Nt + t] -= circ_.real;
  1419. else circ_vec[d * Nt + t] -= circ_.imag;
  1420. }
  1421. }
  1422. return circ_;
  1423. };
  1424. auto complex_vec_prod = [&SurfDim,&SurfDsp] (sctl::Vector<Real>& v, Real c0, Real c1) {
  1425. sctl::Long Nsurf = SurfDim.Dim();
  1426. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  1427. sctl::Long N = SurfDsp[Nsurf-1]+SurfDim[Nsurf-1];
  1428. sctl::Long dof = v.Dim() / (N * 2);
  1429. SCTL_ASSERT(v.Dim() == N * dof * 2);
  1430. for (sctl::Long i = 0; i < Nsurf; i++) {
  1431. for (sctl::Long k = 0; k < dof; k++) {
  1432. sctl::Long offset = SurfDsp[i]*dof*2 + k*2*SurfDim[i];
  1433. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  1434. Real v0 = v[offset + 0*SurfDim[i] + j];
  1435. Real v1 = v[offset + 1*SurfDim[i] + j];
  1436. Real cv0 = v0 * c0 - v1 * c1;
  1437. Real cv1 = v0 * c1 + v1 * c0;
  1438. v[offset + 0*SurfDim[i] + j] = cv0;
  1439. v[offset + 1*SurfDim[i] + j] = cv1;
  1440. }
  1441. }
  1442. }
  1443. };
  1444. auto real_imag_part = [&SurfDim,&SurfDsp] (sctl::Vector<Real>& w, const sctl::Vector<Real>& v, bool real_part) {
  1445. sctl::Long Nsurf = SurfDim.Dim();
  1446. SCTL_ASSERT(SurfDsp.Dim() == Nsurf);
  1447. sctl::Long N = SurfDsp[Nsurf-1]+SurfDim[Nsurf-1];
  1448. sctl::Long dof = v.Dim() / (N * 2);
  1449. SCTL_ASSERT(v.Dim() == N * dof * 2);
  1450. if (w.Dim() != N * dof) w.ReInit(N * dof);
  1451. for (sctl::Long i = 0; i < Nsurf; i++) {
  1452. for (sctl::Long k = 0; k < dof; k++) {
  1453. sctl::Long offset = SurfDsp[i]*dof;
  1454. for (sctl::Long j = 0; j < SurfDim[i]; j++) {
  1455. w[offset + k*SurfDim[i] + j] = v[offset*2 + (k*2+(real_part?0:1))*SurfDim[i] + j];
  1456. }
  1457. }
  1458. }
  1459. };
  1460. auto print_imag_norm = [&real_imag_part] (const sctl::Vector<Real>& B) { // Print | imag(B) |_inf
  1461. #ifdef BIEST_VERBOSE
  1462. sctl::Vector<Real> B_imag;
  1463. real_imag_part(B_imag, B, false);
  1464. std::cout<<"Error : | imag(B) |_inf / | real(B) |_inf = "<<max_norm(B_imag) / max_norm(B)<<'\n';
  1465. #endif
  1466. };
  1467. if (Nsurf == 1) {
  1468. if (B_out.Dim() < 1) B_out.ReInit(1);
  1469. if (m_out.Dim() < 1) m_out.ReInit(1);
  1470. if (sigma_out.Dim() < 1) sigma_out.ReInit(1);
  1471. // TODO: change flux evaluation only on curve
  1472. sctl::Complex<Real> tor_flux = compute_pol_circ(nullptr, B_flux[0], 0) / lambda;
  1473. sctl::Complex<Real> scal = sctl::Complex<Real>(1,0) / tor_flux;
  1474. complex_vec_prod(B[0], scal.real, scal.imag);
  1475. complex_vec_prod(m[0], scal.real, scal.imag);
  1476. complex_vec_prod(sigma[0], scal.real, scal.imag);
  1477. real_imag_part(B_out[0], B[0], true);
  1478. sigma_out[0] = sigma[0];
  1479. m_out[0] = m[0];
  1480. print_imag_norm(B[0]);
  1481. } else if (Nsurf == 2) {
  1482. if (B_out.Dim() < 2) B_out.ReInit(2);
  1483. if (m_out.Dim() < 2) m_out.ReInit(2);
  1484. if (sigma_out.Dim() < 2) sigma_out.ReInit(2);
  1485. sctl::Complex<Real> tor_flux0 = (compute_pol_circ(nullptr, B_flux[0], OuterSurfIdx) - compute_pol_circ(nullptr, B_flux[0], InnerSurfIdx)) / lambda;
  1486. sctl::Complex<Real> tor_flux1 = (compute_pol_circ(nullptr, B_flux[1], OuterSurfIdx) - compute_pol_circ(nullptr, B_flux[1], InnerSurfIdx)) / lambda;
  1487. sctl::Complex<Real> pol_flux0 = (compute_tor_circ(nullptr, B_flux[0], OuterSurfIdx) - compute_tor_circ(nullptr, B_flux[0], InnerSurfIdx)) / lambda;
  1488. sctl::Complex<Real> pol_flux1 = (compute_tor_circ(nullptr, B_flux[1], OuterSurfIdx) - compute_tor_circ(nullptr, B_flux[1], InnerSurfIdx)) / lambda;
  1489. sctl::Matrix<sctl::Complex<Real>> M(2,2);
  1490. M[0][0] = tor_flux0; M[0][1] = tor_flux1;
  1491. M[1][0] = pol_flux0; M[1][1] = pol_flux1;
  1492. sctl::Matrix<sctl::Complex<Real>> M_inv(2,2);
  1493. sctl::Complex<Real> det = M[0][0]*M[1][1] - M[0][1]*M[1][0];
  1494. M_inv[0][0] = M[1][1]/det; M_inv[0][1] =-M[0][1]/det;
  1495. M_inv[1][0] =-M[1][0]/det; M_inv[1][1] = M[0][0]/det;
  1496. auto ComplexMatVec2x2 = [&complex_vec_prod](sctl::Vector<sctl::Vector<Real>>& Vout, const sctl::Vector<sctl::Vector<Real>>& Vin, const sctl::Matrix<sctl::Complex<Real>>& M) {
  1497. SCTL_ASSERT(Vin.Dim() == 2 && Vout.Dim() == 2);
  1498. SCTL_ASSERT(M.Dim(0) == 2 && M.Dim(1) == 2);
  1499. sctl::Vector<Real> V0, V1;
  1500. V0 = Vin[0]; V1 = Vin[1];
  1501. complex_vec_prod(V0, M[0][0].real, M[0][0].imag);
  1502. complex_vec_prod(V1, M[1][0].real, M[1][0].imag);
  1503. Vout[0] = V0 + V1;
  1504. V0 = Vin[0]; V1 = Vin[1];
  1505. complex_vec_prod(V0, M[0][1].real, M[0][1].imag);
  1506. complex_vec_prod(V1, M[1][1].real, M[1][1].imag);
  1507. Vout[1] = V0 + V1;
  1508. };
  1509. sctl::Vector<sctl::Vector<Real>> B_(2);
  1510. ComplexMatVec2x2(B_, B, M_inv);
  1511. ComplexMatVec2x2(m_out, m, M_inv);
  1512. ComplexMatVec2x2(sigma_out, sigma, M_inv);
  1513. real_imag_part(B_out[0], B_[0], true);
  1514. real_imag_part(B_out[1], B_[1], true);
  1515. print_imag_norm(B_[0]);
  1516. print_imag_norm(B_[1]);
  1517. } else {
  1518. SCTL_ASSERT(false);
  1519. }
  1520. }
  1521. sctl::Profile::Toc();
  1522. }
  1523. };
  1524. }
  1525. #endif //_BIE_SOLVERS_HPP_