ngsolve 6.2.2501.post39.dev1__cp312-cp312-macosx_10_15_universal2.whl → 6.2.2501.post48.dev1__cp312-cp312-macosx_10_15_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ngsolve might be problematic. Click here for more details.

Files changed (285) hide show
  1. netgen/include/arnoldi.hpp +55 -0
  2. netgen/include/bandmatrix.hpp +334 -0
  3. netgen/include/basematrix.hpp +957 -0
  4. netgen/include/basevector.hpp +1268 -0
  5. netgen/include/bdbequations.hpp +2752 -0
  6. netgen/include/bdbintegrator.hpp +1660 -0
  7. netgen/include/bessel.hpp +1064 -0
  8. netgen/include/bilinearform.hpp +963 -0
  9. netgen/include/bla.hpp +29 -0
  10. netgen/include/blockalloc.hpp +95 -0
  11. netgen/include/blockjacobi.hpp +316 -0
  12. netgen/include/bspline.hpp +114 -0
  13. netgen/include/calcinverse.hpp +141 -0
  14. netgen/include/cg.hpp +368 -0
  15. netgen/include/chebyshev.hpp +44 -0
  16. netgen/include/cholesky.hpp +720 -0
  17. netgen/include/clapack.h +7254 -0
  18. netgen/include/code_generation.hpp +296 -0
  19. netgen/include/coefficient.hpp +2033 -0
  20. netgen/include/coefficient_impl.hpp +19 -0
  21. netgen/include/coefficient_stdmath.hpp +167 -0
  22. netgen/include/commutingAMG.hpp +106 -0
  23. netgen/include/comp.hpp +79 -0
  24. netgen/include/compatibility.hpp +41 -0
  25. netgen/include/complex_wrapper.hpp +73 -0
  26. netgen/include/compressedfespace.hpp +110 -0
  27. netgen/include/contact.hpp +231 -0
  28. netgen/include/diagonalmatrix.hpp +154 -0
  29. netgen/include/differentialoperator.hpp +276 -0
  30. netgen/include/diffop.hpp +1286 -0
  31. netgen/include/diffop_impl.hpp +326 -0
  32. netgen/include/discontinuous.hpp +84 -0
  33. netgen/include/dump.hpp +949 -0
  34. netgen/include/eigen.hpp +60 -0
  35. netgen/include/eigensystem.hpp +18 -0
  36. netgen/include/elasticity_equations.hpp +595 -0
  37. netgen/include/elementbyelement.hpp +195 -0
  38. netgen/include/elementtopology.hpp +1760 -0
  39. netgen/include/elementtransformation.hpp +339 -0
  40. netgen/include/evalfunc.hpp +405 -0
  41. netgen/include/expr.hpp +1655 -0
  42. netgen/include/facetfe.hpp +175 -0
  43. netgen/include/facetfespace.hpp +178 -0
  44. netgen/include/facethofe.hpp +111 -0
  45. netgen/include/facetsurffespace.hpp +112 -0
  46. netgen/include/fe_interfaces.hpp +32 -0
  47. netgen/include/fem.hpp +87 -0
  48. netgen/include/fesconvert.hpp +14 -0
  49. netgen/include/fespace.hpp +1445 -0
  50. netgen/include/finiteelement.hpp +286 -0
  51. netgen/include/globalinterfacespace.hpp +77 -0
  52. netgen/include/globalspace.hpp +115 -0
  53. netgen/include/gridfunction.hpp +525 -0
  54. netgen/include/h1amg.hpp +41 -0
  55. netgen/include/h1hofe.hpp +188 -0
  56. netgen/include/h1hofe_impl.hpp +1262 -0
  57. netgen/include/h1hofefo.hpp +148 -0
  58. netgen/include/h1hofefo_impl.hpp +185 -0
  59. netgen/include/h1hofespace.hpp +167 -0
  60. netgen/include/h1lofe.hpp +1237 -0
  61. netgen/include/h1lumping.hpp +35 -0
  62. netgen/include/hcurl_equations.hpp +1352 -0
  63. netgen/include/hcurlcurlfe.hpp +2221 -0
  64. netgen/include/hcurlcurlfespace.hpp +78 -0
  65. netgen/include/hcurlfe.hpp +259 -0
  66. netgen/include/hcurlfe_utils.hpp +107 -0
  67. netgen/include/hcurlhdiv_dshape.hpp +857 -0
  68. netgen/include/hcurlhdivfes.hpp +308 -0
  69. netgen/include/hcurlhofe.hpp +175 -0
  70. netgen/include/hcurlhofe_impl.hpp +1871 -0
  71. netgen/include/hcurlhofespace.hpp +193 -0
  72. netgen/include/hcurllofe.hpp +1146 -0
  73. netgen/include/hdiv_equations.hpp +865 -0
  74. netgen/include/hdivdivfe.hpp +2923 -0
  75. netgen/include/hdivdivsurfacespace.hpp +76 -0
  76. netgen/include/hdivfe.hpp +206 -0
  77. netgen/include/hdivfe_utils.hpp +716 -0
  78. netgen/include/hdivfes.hpp +75 -0
  79. netgen/include/hdivhofe.hpp +447 -0
  80. netgen/include/hdivhofe_impl.hpp +1107 -0
  81. netgen/include/hdivhofefo.hpp +229 -0
  82. netgen/include/hdivhofespace.hpp +175 -0
  83. netgen/include/hdivhosurfacefespace.hpp +106 -0
  84. netgen/include/hdivlofe.hpp +773 -0
  85. netgen/include/hidden.hpp +74 -0
  86. netgen/include/householder.hpp +181 -0
  87. netgen/include/hypre_ams_precond.hpp +123 -0
  88. netgen/include/hypre_precond.hpp +73 -0
  89. netgen/include/integrator.hpp +2024 -0
  90. netgen/include/integratorcf.hpp +253 -0
  91. netgen/include/interpolate.hpp +49 -0
  92. netgen/include/intrule.hpp +2541 -0
  93. netgen/include/irspace.hpp +49 -0
  94. netgen/include/jacobi.hpp +136 -0
  95. netgen/include/l2hofe.hpp +193 -0
  96. netgen/include/l2hofe_impl.hpp +564 -0
  97. netgen/include/l2hofefo.hpp +542 -0
  98. netgen/include/l2hofespace.hpp +344 -0
  99. netgen/include/la.hpp +38 -0
  100. netgen/include/linearform.hpp +266 -0
  101. netgen/include/matrix.hpp +2140 -0
  102. netgen/include/memusage.hpp +41 -0
  103. netgen/include/meshaccess.hpp +1358 -0
  104. netgen/include/mgpre.hpp +204 -0
  105. netgen/include/mptools.hpp +2145 -0
  106. netgen/include/multigrid.hpp +42 -0
  107. netgen/include/multivector.hpp +447 -0
  108. netgen/include/mumpsinverse.hpp +187 -0
  109. netgen/include/mycomplex.hpp +361 -0
  110. netgen/include/ng_lapack.hpp +1661 -0
  111. netgen/include/ngblas.hpp +1099 -0
  112. netgen/include/ngs_defines.hpp +30 -0
  113. netgen/include/ngs_stdcpp_include.hpp +106 -0
  114. netgen/include/ngs_utils.hpp +121 -0
  115. netgen/include/ngsobject.hpp +1019 -0
  116. netgen/include/ngsstream.hpp +113 -0
  117. netgen/include/ngstd.hpp +72 -0
  118. netgen/include/nodalhofe.hpp +96 -0
  119. netgen/include/nodalhofe_impl.hpp +141 -0
  120. netgen/include/normalfacetfe.hpp +223 -0
  121. netgen/include/normalfacetfespace.hpp +98 -0
  122. netgen/include/normalfacetsurfacefespace.hpp +84 -0
  123. netgen/include/order.hpp +251 -0
  124. netgen/include/parallel_matrices.hpp +222 -0
  125. netgen/include/paralleldofs.hpp +340 -0
  126. netgen/include/parallelngs.hpp +23 -0
  127. netgen/include/parallelvector.hpp +269 -0
  128. netgen/include/pardisoinverse.hpp +200 -0
  129. netgen/include/periodic.hpp +125 -0
  130. netgen/include/plateaufespace.hpp +25 -0
  131. netgen/include/pml.hpp +275 -0
  132. netgen/include/pmltrafo.hpp +631 -0
  133. netgen/include/postproc.hpp +142 -0
  134. netgen/include/precomp.hpp +60 -0
  135. netgen/include/preconditioner.hpp +602 -0
  136. netgen/include/prolongation.hpp +235 -0
  137. netgen/include/python_comp.hpp +107 -0
  138. netgen/include/python_fem.hpp +89 -0
  139. netgen/include/python_linalg.hpp +58 -0
  140. netgen/include/python_ngstd.hpp +385 -0
  141. netgen/include/recursive_pol.hpp +4844 -0
  142. netgen/include/recursive_pol_tet.hpp +395 -0
  143. netgen/include/recursive_pol_trig.hpp +492 -0
  144. netgen/include/reorderedfespace.hpp +81 -0
  145. netgen/include/sample_sort.hpp +105 -0
  146. netgen/include/scalarfe.hpp +335 -0
  147. netgen/include/shapefunction_utils.hpp +113 -0
  148. netgen/include/simd_complex.hpp +284 -0
  149. netgen/include/smoother.hpp +253 -0
  150. netgen/include/solve.hpp +89 -0
  151. netgen/include/sparsecholesky.hpp +313 -0
  152. netgen/include/sparsematrix.hpp +1038 -0
  153. netgen/include/sparsematrix_dyn.hpp +91 -0
  154. netgen/include/sparsematrix_impl.hpp +920 -0
  155. netgen/include/special_matrix.hpp +461 -0
  156. netgen/include/specialelement.hpp +125 -0
  157. netgen/include/statushandler.hpp +33 -0
  158. netgen/include/stringops.hpp +12 -0
  159. netgen/include/superluinverse.hpp +136 -0
  160. netgen/include/symbolicintegrator.hpp +849 -0
  161. netgen/include/symmetricmatrix.hpp +144 -0
  162. netgen/include/tangentialfacetfe.hpp +224 -0
  163. netgen/include/tangentialfacetfespace.hpp +106 -0
  164. netgen/include/tensor.hpp +522 -0
  165. netgen/include/tensorcoefficient.hpp +446 -0
  166. netgen/include/tensorproductintegrator.hpp +113 -0
  167. netgen/include/thcurlfe.hpp +128 -0
  168. netgen/include/thcurlfe_impl.hpp +380 -0
  169. netgen/include/thdivfe.hpp +80 -0
  170. netgen/include/thdivfe_impl.hpp +426 -0
  171. netgen/include/tpdiffop.hpp +461 -0
  172. netgen/include/tpfes.hpp +133 -0
  173. netgen/include/tpintrule.hpp +224 -0
  174. netgen/include/triangular.hpp +465 -0
  175. netgen/include/tscalarfe.hpp +245 -0
  176. netgen/include/tscalarfe_impl.hpp +1029 -0
  177. netgen/include/umfpackinverse.hpp +148 -0
  178. netgen/include/vector.hpp +1219 -0
  179. netgen/include/voxelcoefficientfunction.hpp +41 -0
  180. netgen/include/vtkoutput.hpp +198 -0
  181. netgen/include/vvector.hpp +208 -0
  182. netgen/include/webgui.hpp +92 -0
  183. netgen/libngbla.dylib +0 -0
  184. netgen/libngcomp.dylib +0 -0
  185. netgen/libngfem.dylib +0 -0
  186. netgen/libngla.dylib +0 -0
  187. netgen/libngsolve.dylib +0 -0
  188. netgen/libngstd.dylib +0 -0
  189. ngsolve/__init__.pyi +231 -0
  190. ngsolve/bla.pyi +1139 -0
  191. ngsolve/bvp.pyi +32 -0
  192. ngsolve/cmake/NGSolveConfig.cmake +102 -0
  193. ngsolve/cmake/ngsolve-targets-release.cmake +69 -0
  194. ngsolve/cmake/ngsolve-targets.cmake +163 -0
  195. ngsolve/comp/__init__.pyi +5382 -0
  196. ngsolve/comp/pml.pyi +89 -0
  197. ngsolve/config/__init__.py +1 -0
  198. ngsolve/config/__init__.pyi +43 -0
  199. ngsolve/config/__main__.py +4 -0
  200. ngsolve/config/config.py +60 -0
  201. ngsolve/config/config.pyi +45 -0
  202. ngsolve/demos/TensorProduct/__init__.py +0 -0
  203. ngsolve/demos/TensorProduct/tp_dg_1d_1d.py +80 -0
  204. ngsolve/demos/TensorProduct/tp_dg_1d_2d.py +73 -0
  205. ngsolve/demos/TensorProduct/tp_dg_2d_1d.py +72 -0
  206. ngsolve/demos/TensorProduct/tp_dg_2d_2d.py +66 -0
  207. ngsolve/demos/__init__.py +0 -0
  208. ngsolve/demos/howto/__init__.py +0 -0
  209. ngsolve/demos/howto/hhj.py +44 -0
  210. ngsolve/demos/howto/hybrid_dg.py +53 -0
  211. ngsolve/demos/howto/mixed.py +30 -0
  212. ngsolve/demos/howto/nonlin.py +29 -0
  213. ngsolve/demos/howto/pickling.py +26 -0
  214. ngsolve/demos/howto/pml.py +31 -0
  215. ngsolve/demos/howto/taskmanager.py +20 -0
  216. ngsolve/demos/howto/tdnns.py +47 -0
  217. ngsolve/demos/howto/timeDG-skeleton.py +45 -0
  218. ngsolve/demos/howto/timeDG.py +38 -0
  219. ngsolve/demos/howto/timeDGlap.py +42 -0
  220. ngsolve/demos/howto/timeDGwave.py +61 -0
  221. ngsolve/demos/intro/__init__.py +0 -0
  222. ngsolve/demos/intro/adaptive.py +123 -0
  223. ngsolve/demos/intro/cmagnet.py +62 -0
  224. ngsolve/demos/intro/elasticity.py +76 -0
  225. ngsolve/demos/intro/navierstokes.py +74 -0
  226. ngsolve/demos/intro/poisson.ipynb +170 -0
  227. ngsolve/demos/intro/poisson.py +41 -0
  228. ngsolve/demos/mpi/__init__.py +0 -0
  229. ngsolve/demos/mpi/mpi_cmagnet.py +87 -0
  230. ngsolve/demos/mpi/mpi_navierstokes.py +117 -0
  231. ngsolve/demos/mpi/mpi_poisson.py +89 -0
  232. ngsolve/demos/mpi/mpi_timeDG.py +82 -0
  233. ngsolve/directsolvers.pyi +15 -0
  234. ngsolve/eigenvalues.pyi +30 -0
  235. ngsolve/fem.pyi +1707 -0
  236. ngsolve/krylovspace.pyi +301 -0
  237. ngsolve/la.pyi +1218 -0
  238. ngsolve/ngslib.so +0 -0
  239. ngsolve/ngstd.pyi +58 -0
  240. ngsolve/nonlinearsolvers.pyi +97 -0
  241. ngsolve/preconditioners.pyi +6 -0
  242. ngsolve/solve.pyi +108 -0
  243. ngsolve/solvers.pyi +14 -0
  244. ngsolve/timestepping.pyi +27 -0
  245. ngsolve/timing.pyi +54 -0
  246. ngsolve/utils.pyi +279 -0
  247. ngsolve-6.2.2501.post48.dev1.data/data/Netgen.icns +0 -0
  248. ngsolve-6.2.2501.post48.dev1.data/data/bin/ngscxx +17 -0
  249. ngsolve-6.2.2501.post48.dev1.data/data/bin/ngsld +13 -0
  250. ngsolve-6.2.2501.post48.dev1.data/data/bin/ngsolve.tcl +648 -0
  251. ngsolve-6.2.2501.post48.dev1.data/data/bin/ngspy +2 -0
  252. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/beam.geo +17 -0
  253. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/beam.vol +240 -0
  254. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/chip.in2d +41 -0
  255. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/chip.vol +614 -0
  256. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coil.geo +12 -0
  257. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coil.vol +2560 -0
  258. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coilshield.geo +24 -0
  259. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coilshield.vol +3179 -0
  260. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/cube.geo +19 -0
  261. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/cube.vol +1832 -0
  262. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d10_DGdoubleglazing.pde +50 -0
  263. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d11_chip_nitsche.pde +40 -0
  264. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d1_square.pde +43 -0
  265. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d2_chip.pde +35 -0
  266. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d3_helmholtz.pde +22 -0
  267. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d4_cube.pde +46 -0
  268. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d5_beam.pde +74 -0
  269. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d6_shaft.pde +73 -0
  270. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d7_coil.pde +50 -0
  271. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d8_coilshield.pde +49 -0
  272. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d9_hybridDG.pde +72 -0
  273. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/doubleglazing.in2d +27 -0
  274. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/doubleglazing.vol +737 -0
  275. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/piezo2d40round4.vol.gz +0 -0
  276. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/shaft.geo +73 -0
  277. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/shaft.vol +4291 -0
  278. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/square.in2d +17 -0
  279. ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/square.vol +149 -0
  280. {ngsolve-6.2.2501.post39.dev1.dist-info → ngsolve-6.2.2501.post48.dev1.dist-info}/METADATA +2 -2
  281. ngsolve-6.2.2501.post48.dev1.dist-info/RECORD +304 -0
  282. ngsolve-6.2.2501.post39.dev1.dist-info/RECORD +0 -25
  283. {ngsolve-6.2.2501.post39.dev1.dist-info → ngsolve-6.2.2501.post48.dev1.dist-info}/LICENSE +0 -0
  284. {ngsolve-6.2.2501.post39.dev1.dist-info → ngsolve-6.2.2501.post48.dev1.dist-info}/WHEEL +0 -0
  285. {ngsolve-6.2.2501.post39.dev1.dist-info → ngsolve-6.2.2501.post48.dev1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,2145 @@
1
+ #ifndef FILE_MPTOOLS
2
+ #define FILE_MPTOOLS
3
+
4
+ /*
5
+ tools for computing with spherical harmonics and multi-poles
6
+ */
7
+
8
+
9
+ #include <bla.hpp>
10
+ #include <coefficient.hpp>
11
+
12
+
13
+ namespace ngfem
14
+ {
15
+
16
+
17
+
18
+ class SphericalHarmonics
19
+ {
20
+ int order;
21
+ Vector<Complex> coefs;
22
+
23
+ public:
24
+ SphericalHarmonics (int aorder)
25
+ : order(aorder), coefs(sqr(order+1)) { coefs=0.0; }
26
+
27
+ int Order() const { return order; }
28
+ FlatVector<Complex> Coefs() const { return coefs; }
29
+
30
+ Complex & Coef(int n, int m)
31
+ {
32
+ return coefs(n*(n+1) + m);
33
+ }
34
+
35
+ auto CoefsN (int n) const
36
+ {
37
+ return FlatVector<Complex> (2*n+1, &coefs(n*(n+1)-n));
38
+ }
39
+
40
+ auto Polar (Vec<3> x) const
41
+ {
42
+ double phi, theta;
43
+ if (x(0) == 0 && x(1) == 0)
44
+ {
45
+ phi = 0;
46
+ theta = x(2) > 0 ? 0 : M_PI;
47
+ }
48
+ else
49
+ {
50
+ phi = atan2(x(1), x(0));
51
+ theta = acos(x(2)/L2Norm(x));
52
+ }
53
+ return tuple{theta, phi};
54
+ }
55
+
56
+ Complex Eval (Vec<3> x) const
57
+ {
58
+ auto [theta, phi] = Polar(x);
59
+ return Eval(theta, phi);
60
+ }
61
+
62
+ Complex Eval (double theta, double phi) const
63
+ {
64
+ static Timer t("mptool sh evaluate"); RegionTimer rg(t);
65
+
66
+ Matrix legfunc(order+1, order+1);
67
+ NormalizedLegendreFunctions (order, order, cos(theta), legfunc);
68
+ Vector<Complex> exp_imphi(order+1);
69
+ Complex exp_iphi(cos(phi), sin(phi));
70
+ Complex prod = 1.0;
71
+ for (int i = 0; i <= order; i++)
72
+ {
73
+ exp_imphi(i) = prod;
74
+ prod *= -exp_iphi;
75
+ }
76
+
77
+ Complex sum = 0.0;
78
+ int ii = 0;
79
+ for (int n = 0; n <= order; n++)
80
+ {
81
+ for (int m = -n; m < 0; m++, ii++)
82
+ sum += coefs(ii) * conj(exp_imphi(-m)) * legfunc(-m, n);
83
+ for (int m = 0; m <= n; m++, ii++)
84
+ sum += coefs(ii) * exp_imphi(m) * legfunc(m, n);
85
+ }
86
+
87
+ sum /= sqrt(4*M_PI);
88
+ return sum;
89
+ }
90
+
91
+
92
+
93
+ Complex EvalOrder (int n, Vec<3> x) const
94
+ {
95
+ auto [theta, phi] = Polar (x);
96
+ return EvalOrder(n, theta, phi);
97
+ }
98
+
99
+ Complex EvalOrder (int n, double theta, double phi) const
100
+ {
101
+ static Timer t("mptool sh evalorder");
102
+
103
+ RegionTimer rg(t);
104
+
105
+ Matrix legfunc(order+1, order+1);
106
+ NormalizedLegendreFunctions (order, order, cos(theta), legfunc);
107
+ Vector<Complex> exp_imphi(order+1);
108
+ Complex exp_iphi(cos(phi), sin(phi));
109
+ Complex prod = 1.0;
110
+ for (int i = 0; i <= order; i++)
111
+ {
112
+ exp_imphi(i) = prod;
113
+ prod *= -exp_iphi;
114
+ }
115
+
116
+ Complex sum = 0.0;
117
+ auto coefsn = CoefsN(n);
118
+ int ii = 0;
119
+ // for (int n = 0; n <= order; n++)
120
+ {
121
+ for (int m = -n; m < 0; m++, ii++)
122
+ sum += coefsn(ii) * conj(exp_imphi(-m)) * legfunc(-m, n);
123
+ for (int m = 0; m <= n; m++, ii++)
124
+ sum += coefsn(ii) * exp_imphi(m) * legfunc(m, n);
125
+ }
126
+
127
+ sum /= sqrt(4*M_PI);
128
+ return sum;
129
+ }
130
+
131
+
132
+
133
+ void EvalOrders (Vec<3> x, FlatVector<Complex> vals) const
134
+ {
135
+ auto [theta, phi] = Polar(x);
136
+ return EvalOrders(theta, phi, vals);
137
+ }
138
+
139
+ void EvalOrders (double theta, double phi, FlatVector<Complex> vals) const
140
+ {
141
+ static Timer ts("mptool sh evalorders small");
142
+ static Timer tl("mptool sh evalorders large");
143
+ // RegionTimer rg(order < 30 ? ts : tl);
144
+ // if (order > 30) tl.Start();
145
+
146
+ Matrix legfunc(order+1, order+1);
147
+ NormalizedLegendreFunctions (order, order, cos(theta), legfunc);
148
+ Vector<Complex> exp_imphi(order+1);
149
+ Complex exp_iphi(cos(phi), sin(phi));
150
+ Complex prod = 1.0;
151
+ for (int i = 0; i <= order; i++)
152
+ {
153
+ exp_imphi(i) = prod;
154
+ prod *= -exp_iphi;
155
+ }
156
+
157
+
158
+ for (int n = 0; n <= order; n++)
159
+ {
160
+ auto coefsn = CoefsN(n);
161
+ int ii = 0;
162
+
163
+ Complex sum = 0.0;
164
+ for (int m = -n; m < 0; m++, ii++)
165
+ sum += coefsn(ii) * conj(exp_imphi(-m)) * legfunc(-m, n);
166
+ for (int m = 0; m <= n; m++, ii++)
167
+ sum += coefsn(ii) * exp_imphi(m) * legfunc(m, n);
168
+ vals(n) = sum;
169
+ }
170
+
171
+ vals /= sqrt(4*M_PI);
172
+
173
+ // if (order > 30) tl.Stop();
174
+ }
175
+
176
+
177
+ void Calc (Vec<3> x, FlatVector<Complex> shapes)
178
+ {
179
+ auto [theta, phi] = Polar(x);
180
+
181
+ Matrix legfunc(order+1, order+1);
182
+ NormalizedLegendreFunctions (order, order, cos(theta), legfunc);
183
+ Vector<Complex> exp_imphi(order+1);
184
+ Complex exp_iphi(cos(phi), sin(phi));
185
+ Complex prod = 1.0;
186
+ for (int i = 0; i <= order; i++)
187
+ {
188
+ exp_imphi(i) = prod;
189
+ prod *= -exp_iphi;
190
+ }
191
+
192
+ int ii = 0;
193
+ for (int n = 0; n <= order; n++)
194
+ {
195
+ for (int m = -n; m < 0; m++, ii++)
196
+ shapes(ii) = conj(exp_imphi(-m)) * legfunc(-m, n);
197
+ for (int m = 0; m <= n; m++, ii++)
198
+ shapes(ii) = exp_imphi(m) * legfunc(m, n);
199
+ }
200
+
201
+ shapes /= sqrt(4*M_PI);
202
+ }
203
+
204
+
205
+ void RotateZ (double alpha)
206
+ {
207
+ // static Timer t("mptool sh RotateZ"); RegionTimer rg(t);
208
+ if (order < 0) return;
209
+
210
+ Vector<Complex> exp_imalpha(order+1);
211
+ Complex exp_ialpha(cos(alpha), sin(alpha));
212
+ Complex prod = 1.0;
213
+ for (int i = 0; i <= order; i++)
214
+ {
215
+ exp_imalpha(i) = prod;
216
+ prod *= exp_ialpha;
217
+ }
218
+
219
+ int ii = 0;
220
+ for (int n = 0; n <= order; n++)
221
+ {
222
+ for (int m = -n; m < 0; m++, ii++)
223
+ coefs(ii) *= conj(exp_imalpha(-m));
224
+ for (int m = 0; m <= n; m++, ii++)
225
+ coefs(ii) *= exp_imalpha(m);
226
+ }
227
+ }
228
+
229
+
230
+
231
+
232
+ static double CalcAmn (int m, int n)
233
+ {
234
+ if (m < 0) m=-m;
235
+ if (n < m) return 0;
236
+ return sqrt( (n+1.0+m)*(n+1.0-m) / ( (2*n+1)*(2*n+3) ));
237
+ }
238
+
239
+ static double CalcBmn (int m, int n)
240
+ {
241
+ double sgn = (m >= 0) ? 1 : -1;
242
+ if ( (m > n) || (-m > n) ) return 0;
243
+ return sgn * sqrt( (n-m-1.0)*(n-m) / ( (2*n-1.0)*(2*n+1)));
244
+ }
245
+
246
+ static double CalcDmn (int m, int n)
247
+ {
248
+ double sgn = (m >= 0) ? 1 : -1;
249
+ return sgn/2 * sqrt((n-m)*(n+m+1));
250
+ }
251
+
252
+
253
+ void RotateY (double alpha)
254
+ {
255
+ LocalHeap lh(8*6*sqr(order) + 8*15*order + 500);
256
+
257
+ static Timer t("mptool sh RotateY"); RegionTimer rg(t);
258
+
259
+ double s = sin(alpha);
260
+ double c = cos(alpha);
261
+
262
+ FlatMatrix<> normalized_leg_func(order+2, order+2, lh);
263
+ NormalizedLegendreFunctions(order+1, order+1, c, normalized_leg_func);
264
+
265
+ if (alpha < 0)
266
+ for (int i = 1; i <= order+1; i+=2)
267
+ normalized_leg_func.Row(i) *= -1;
268
+
269
+ // cout << "leg = " << endl << normalized_leg_func << endl;
270
+ FlatVector<> Dmn(2*order+1, lh);
271
+
272
+ for (int n=1; n <= order; n++)
273
+ {
274
+ HeapReset hr(lh);
275
+
276
+ FlatMatrix<double> trafo(n+1, 2*n+1, lh);
277
+ /*
278
+ Recursive Computation of Spherical Harmonic Rotation Coefficients of Large Degree
279
+ Nail A. Gumerov and Ramani Duraiswami
280
+ within Excursions in Harmonic Analysis, Volume 3
281
+
282
+ page 130
283
+ */
284
+
285
+ // Step 2
286
+ // H(0,m)
287
+ trafo.Col(n) = 1.0/sqrt(2*n+1) * normalized_leg_func.Col(n).Range(n+1);
288
+ for (int m = 1; m <= n; m += 2) trafo(m,n) *= -1;
289
+ // Step 3
290
+ // H(1,m)
291
+ FlatVector<double> tmp = 1.0/sqrt(2*n+3) * normalized_leg_func.Col(n+1).Range(n+2) | lh;
292
+ for (int m = 1; m < tmp.Size(); m += 2) tmp(m) *= -1;
293
+ for (int m = 1; m <= n; m++)
294
+ trafo.Col(n+1)(m) = 1/CalcBmn(0,n+1) * ( CalcBmn(-m-1, n+1)*(1-c)/2 * tmp(m+1)
295
+ - CalcBmn(m-1,n+1)*(1+c)/2 * tmp(m-1)
296
+ - CalcAmn(m,n) * s*tmp(m));
297
+
298
+ // Step 4
299
+ // diamond - recursion
300
+ for (int mp = -n; mp <= n; mp++)
301
+ Dmn(order+mp) = CalcDmn(mp, n);
302
+
303
+ for (int mp = 1; mp < n; mp++)
304
+ {
305
+ double invDmn = 1.0 / Dmn(order+mp);
306
+ for (int m = mp; m < n; m++)
307
+ trafo(m, n+mp+1) = invDmn * ( Dmn(order+mp-1) *trafo(m ,n+mp-1)
308
+ -Dmn(order+m-1)*trafo(m-1,n+mp)
309
+ +Dmn(order+m) *trafo(m+1,n+mp));
310
+ int m = n;
311
+ trafo(m, n+mp+1) = invDmn * ( Dmn(order+mp-1,n)*trafo(m ,n+mp-1)
312
+ -Dmn(order+m-1,n)*trafo(m-1,n+mp));
313
+ }
314
+
315
+ // Step 5
316
+ // diamond - recursion, negative
317
+ for (int mp = 0; mp > -n; mp--)
318
+ {
319
+ double invDmn = 1.0 / Dmn(order+mp-1);
320
+ for (int m = -mp+1; m < n; m++)
321
+ trafo(m, n+mp-1) = invDmn * ( Dmn(order+mp,n)*trafo(m ,n+mp+1)
322
+ +Dmn(order+m-1,n)*trafo(m-1,n+mp)
323
+ -Dmn(order+m ,n)*trafo(m+1,n+mp));
324
+ int m = n;
325
+ trafo(m, n+mp-1) = invDmn * ( Dmn(order+mp,n)*trafo(m ,n+mp+1)
326
+ +Dmn(order+m-1,n)*trafo(m-1,n+mp));
327
+ }
328
+ // Step 6
329
+ // symmetries in m and mp
330
+ for (int m = 0; m <= n; m++)
331
+ {
332
+ auto dst = trafo.Row(m).Range(n+m, n+n+1);
333
+ auto src = trafo.Col(n+m).Range(m, n+1);
334
+ dst = src;
335
+ }
336
+ for (int m = 0; m <= n; m++)
337
+ {
338
+ auto dst = trafo.Row(m).Range(n-n, n-m+1).Reversed();
339
+ auto src = trafo.Col(n-m).Range(m, n+1);
340
+ dst = src;
341
+ }
342
+ /*
343
+ double errortho = L2Norm( Matrix(trafo*Trans(trafo) - Identity(n+1)));
344
+ if (errortho > 1e-10)
345
+ {
346
+ *testout << "n = " << n << " order = " << Order() << ", alpha = " << alpha << ", errortho = " << errortho << endl;
347
+ if (n < 10)
348
+ *testout << trafo*Trans(trafo) << endl;
349
+ }
350
+ */
351
+
352
+ FlatVector<Complex> cn = CoefsN(n);
353
+ FlatVector<Complex> old = cn | lh;
354
+
355
+ cn = Trans(trafo) * old.Range(n, 2*n+1);
356
+ cn.Slice(0,1).Reversed() += Trans(trafo.Rows(1,n+1)) * old.Range(0,n).Reversed();
357
+
358
+ for (int m = 1; m <= n; m+=2)
359
+ {
360
+ cn(n+m) *= -1;
361
+ cn(n-m) *= -1;
362
+ }
363
+ }
364
+ }
365
+
366
+ };
367
+
368
+
369
+ // https://fortran-lang.discourse.group/t/looking-for-spherical-bessel-and-hankel-functions-of-first-and-second-kind-and-arbitrary-order/2308/2
370
+
371
+ // adapted from fmm3d
372
+ template <typename Tz>
373
+ void besseljs3d (int nterms, Tz z, double scale,
374
+ FlatVector<Tz> fjs, FlatVector<Tz> fjder)
375
+ {
376
+ /*
377
+ c**********************************************************************
378
+ c
379
+ c PURPOSE:
380
+ c
381
+ c This subroutine evaluates the first NTERMS spherical Bessel
382
+ c functions and if required, their derivatives.
383
+ c It incorporates a scaling parameter SCALE so that
384
+ c
385
+ c fjs_n(z)=j_n(z)/SCALE^n
386
+ c fjder_n(z)=\frac{\partial fjs_n(z)}{\partial z}
387
+ c
388
+ c INPUT:
389
+ c
390
+ c nterms (integer): order of expansion of output array fjs
391
+ c z (complex *16): argument of the spherical Bessel functions
392
+ c scale (real *8) : scaling factor (discussed above)
393
+ c ifder (integer): flag indicating whether to calculate "fjder"
394
+ c 0 NO
395
+ c 1 YES
396
+ c OUTPUT:
397
+ c fjs (complex *16): array of scaled Bessel functions.
398
+ c fjder (complex *16): array of derivs of scaled Bessel functions.
399
+ c
400
+ c
401
+ */
402
+
403
+
404
+ // c ... Initializing ...
405
+
406
+ // set to asymptotic values if argument is sufficiently small
407
+ if (abs(z) < 1e-200)
408
+ {
409
+ fjs(0) = 1;
410
+ for (int i = 1; i <= nterms; i++)
411
+ fjs(i) = 0.0;
412
+
413
+ if (fjder.Size())
414
+ {
415
+ fjder = 0.0;
416
+ fjder(1) = 1.0/(3*scale);
417
+ }
418
+ return;
419
+ }
420
+
421
+
422
+ // ... Step 1: recursion up to find ntop, starting from nterms
423
+
424
+ Tz zinv=1.0/z;
425
+
426
+ Tz fjm1 = 0.0;
427
+ Tz fj0 = 1.0;
428
+
429
+ /*
430
+ c
431
+ cc note max point for upward recurrence is
432
+ c hard coded to nterms + 1000,
433
+ c this might cause loss of accuracy for some
434
+ c arguments in the complex plane for large
435
+ c nterms. For example, it is a terrible idea
436
+ c to use this code for z>>nterms^2
437
+ */
438
+
439
+ // int lwfjs = nterms + 100000;
440
+ int ntop = nterms+1000;
441
+
442
+ for (int i = nterms; ; i++)
443
+ {
444
+ double dcoef = 2*i+1.0;
445
+ Tz fj1 = dcoef*zinv*fj0-fjm1;
446
+ double dd = sqr(abs(fj1));
447
+ if (dd > 1e40)
448
+ {
449
+ ntop=i+1;
450
+ break;
451
+ }
452
+ fjm1 = fj0;
453
+ fj0 = fj1;
454
+ if (i > nterms+100000)
455
+ throw Exception("bessel failed 1");
456
+ }
457
+
458
+ Array<bool> iscale(ntop+1);
459
+ Vector<Tz> fjtmp(ntop+1);
460
+
461
+ /*
462
+ c ... Step 2: Recursion back down to generate the unscaled jfuns:
463
+ c if magnitude exceeds UPBOUND2, rescale and continue the
464
+ c recursion (saving the order at which rescaling occurred
465
+ c in array iscale.
466
+ */
467
+
468
+ iscale = false;
469
+
470
+ fjtmp(ntop) = 0.0;
471
+ fjtmp(ntop-1) = 1.0;
472
+ for (int i = ntop-1; i>=1; i--)
473
+ {
474
+ double dcoef = 2*i+1.0;
475
+ fjtmp(i-1) = dcoef*zinv*fjtmp(i)-fjtmp(i+1);
476
+ double dd = sqr(abs(fjtmp(i-1)));
477
+ if (dd > 1e40)
478
+ {
479
+ fjtmp(i) *= 1e-40;
480
+ fjtmp(i-1) *= 1e-40;
481
+ iscale[i] = true;
482
+ }
483
+ }
484
+
485
+ /*
486
+ c
487
+ c ... Step 3: go back up to the top and make sure that all
488
+ c Bessel functions are scaled by the same factor
489
+ c (i.e. the net total of times rescaling was invoked
490
+ c on the way down in the previous loop).
491
+ c At the same time, add scaling to fjs array.
492
+ c
493
+ */
494
+
495
+ double scalinv = 1.0/scale;
496
+ double sctot = 1.0;
497
+ for (int i = 1; i <= ntop; i++)
498
+ {
499
+ sctot *= scalinv;
500
+ if (iscale[i-1])
501
+ sctot *= 1e-40;
502
+ fjtmp(i) *= sctot;
503
+ }
504
+
505
+ // Determine the normalization parameter:
506
+
507
+ fj0=sin(z)*zinv;
508
+ Tz fj1=fj0*zinv-cos(z)*zinv;
509
+
510
+ double d0=abs(fj0);
511
+ double d1=abs(fj1);
512
+ Tz zscale;
513
+ if (d1 > d0)
514
+ zscale=fj1/(fjtmp(1)*scale);
515
+ else
516
+ zscale=fj0/fjtmp(0);
517
+
518
+ // Scale the jfuns by zscale:
519
+
520
+ Tz ztmp=zscale;
521
+ for (int i = 0; i <= nterms; i++)
522
+ fjs(i)=fjtmp(i)*ztmp;
523
+
524
+
525
+ // Finally, calculate the derivatives if desired:
526
+
527
+ if (fjder.Size())
528
+ {
529
+ fjder(0) = -fjs(1)*scale;
530
+ for (int i = 1; i <= nterms; i++)
531
+ {
532
+ double dc1=i/(2*i+1.0);
533
+ double dc2=1.0-dc1;
534
+ dc1=dc1*scalinv;
535
+ dc2=dc2*scale;
536
+ fjder(i)=(dc1*fjtmp(i-1)-dc2*fjtmp(i+1))*ztmp;
537
+ }
538
+ }
539
+ }
540
+
541
+
542
+
543
+
544
+ /*
545
+ // from A. Barnett
546
+ // http://www.fresco.org.uk/functions/barnett/index.htm
547
+
548
+ spherical bessel functions of first (the j_n) and second (the y_n) kind.
549
+
550
+ j0(r) = sin(r)/r
551
+ j1(r) = (sin(r)-r cos(r)) / r**2
552
+
553
+ y0(r) = -cos(r)/r
554
+ y1(r) = (-cos(r)-r*sin(r)) / r**2
555
+ */
556
+ void SBESJY (double x, int lmax,
557
+ FlatVector<double> j,
558
+ FlatVector<double> y,
559
+ FlatVector<double> jp,
560
+ FlatVector<double> yp)
561
+ {
562
+ if (x < 1e-8)
563
+ {
564
+ cout << "TODO: special treatment for small x" << endl;
565
+ return;
566
+ }
567
+
568
+ double xinv = 1/x;
569
+
570
+ if (lmax > 0)
571
+ {
572
+ double twoxi = 2*xinv;
573
+ double sl = lmax*xinv;
574
+ double tk = 2*sl+3*xinv;
575
+ double cf1 = sl;
576
+ double den = 1;
577
+ if (abs(cf1) < 1e-8) cf1 = 1e-8;
578
+ double c = cf1;
579
+ double d = 0;
580
+ for (int l = 1; l < 10000; l++)
581
+ {
582
+ c = tk-1/c;
583
+ d = tk-d;
584
+ if (abs(c) < 1e-8) c = 1e-8;
585
+ if (abs(d) < 1e-8) d = 1e-8;
586
+ d = 1/d;
587
+ double dcf1 = d*c;
588
+ cf1 *= dcf1;
589
+ if (d < 0) den = -den;
590
+ if (abs(dcf1-1) < 1e-10)
591
+ break;
592
+ tk += twoxi;
593
+ // nfp = l;
594
+ }
595
+
596
+ j(lmax) = den;
597
+ jp(lmax) = cf1*den;
598
+ for (int l = lmax; l >= 1; l--)
599
+ {
600
+ j(l-1) = (sl+xinv)*j(l) + jp(l);
601
+ sl = sl-xinv;
602
+ jp(l-1) = sl*j(l-1) - j(l);
603
+ }
604
+ }
605
+
606
+ double j0 = j(0);
607
+ double jp0 = jp(0);
608
+
609
+ // C------ CALCULATE THE L=0 SPHERICAL BESSEL FUNCTIONS DIRECTLY
610
+ j(0) = xinv * sin(x);
611
+ y(0) = -xinv * cos(x);
612
+ jp(0) = -y(0)-xinv*j(0);
613
+ yp(0) = j(0)-xinv*y(0);
614
+
615
+ double omega = (abs(j0)>abs(jp0)) ? j(0)/j0 : jp(0) / jp0; // fix for x \approx 2 pi
616
+ double sl = 0;
617
+ for (int l = 1; l <=lmax; l++)
618
+ {
619
+ j(l) *= omega;
620
+ jp(l) *= omega;
621
+ y(l) = sl*y(l-1) - yp(l-1);
622
+ sl += xinv;
623
+ yp(l) = y(l-1) - (sl+xinv)*y(l);
624
+ }
625
+ }
626
+
627
+
628
+
629
+ template <typename T>
630
+ void SphericalBessel (int n, double rho, double scale, T && values)
631
+ {
632
+ Vector<double> j(n+1), jp(n+1);
633
+ besseljs3d<double> (n, rho, scale, j, jp);
634
+ values = j;
635
+ }
636
+
637
+
638
+ template <typename T>
639
+ void SphericalHankel1 (int n, double rho, double scale, T && values)
640
+ {
641
+ // Complex imag(0,1);
642
+ /*
643
+ if (n >= 0)
644
+ values(0) = exp(imag*rho) / (imag*rho);
645
+ if (n >= 1)
646
+ values(1) = -imag*values(0)*(1.0-1.0/(imag*rho));
647
+
648
+ for (int i = 2; i <= n; i++)
649
+ values(i) = (2*i-1)/rho * values(i-1) - values(i-2);
650
+ */
651
+
652
+ if (rho < 1e-8)
653
+ {
654
+ values = Complex(0);
655
+ return;
656
+ }
657
+ Vector j(n+1), y(n+1), jp(n+1), yp(n+1);
658
+ SBESJY (rho, n, j, y, jp, yp);
659
+
660
+ values = j + Complex(0,1) * y;
661
+ if (scale != 1.0)
662
+ {
663
+ double prod = 1.0;
664
+ for (int i = 0; i <= n; i++)
665
+ {
666
+ values(i) *= prod;
667
+ prod *= scale;
668
+ }
669
+ }
670
+ }
671
+
672
+
673
+
674
+
675
+
676
+ // hn1 = jn+ i*yn
677
+ class MPSingular
678
+ {
679
+ public:
680
+ template <typename T>
681
+ static void Eval (int order, double r, double scale, T && values)
682
+ {
683
+ SphericalHankel1(order, r, scale, values);
684
+ }
685
+ };
686
+
687
+ // jn
688
+ class MPRegular
689
+ {
690
+ public:
691
+ template <typename T>
692
+ static void Eval (int order, double r, double scale, T && values)
693
+ {
694
+ SphericalBessel (order, r, 1.0/scale, values);
695
+ }
696
+ };
697
+
698
+
699
+
700
+
701
+ template <typename RADIAL>
702
+ class MultiPole
703
+ {
704
+ SphericalHarmonics sh;
705
+ double kappa;
706
+ double scale;
707
+ public:
708
+ MultiPole (int aorder, double akappa, double ascale = 1)
709
+ : sh(aorder), kappa(akappa), scale(ascale) { }
710
+
711
+ Complex & Coef(int n, int m) { return sh.Coef(n,m); }
712
+ auto & SH() { return sh; }
713
+ const auto & SH() const { return sh; }
714
+ double Kappa() const { return kappa; }
715
+ double Scale() const { return scale; }
716
+ int Order() const { return sh.Order(); }
717
+
718
+ MultiPole<RADIAL> Truncate(int neworder) const
719
+ {
720
+ if (neworder > sh.Order()) neworder=sh.Order();
721
+ MultiPole nmp(neworder, kappa);
722
+ nmp.sh.Coefs() = sh.Coefs().Range(sqr(neworder+1));
723
+ return nmp;
724
+ }
725
+
726
+ MultiPole & operator+= (const MultiPole & mp2)
727
+ {
728
+ size_t commonsize = min(SH().Coefs().Size(), mp2.SH().Coefs().Size());
729
+ SH().Coefs().Range(commonsize) += mp2.SH().Coefs().Range(commonsize);
730
+ return *this;
731
+ }
732
+
733
+ Complex Eval (Vec<3> x) const
734
+ {
735
+ if (sh.Order() < 0) return 0;
736
+
737
+ Vector<Complex> radial(sh.Order()+1);
738
+ Vector<Complex> shvals(sh.Order()+1);
739
+
740
+ RADIAL::Eval(sh.Order(), kappa*L2Norm(x), scale, radial);
741
+ sh.EvalOrders (x, shvals);
742
+
743
+ Complex sum = 0;
744
+ for (int i = 0; i <= sh.Order(); i++)
745
+ sum += shvals(i) * radial(i);
746
+
747
+ return sum;
748
+ }
749
+
750
+ void AddCharge (Vec<3> x, Complex c)
751
+ {
752
+ if constexpr (!std::is_same<RADIAL,MPSingular>())
753
+ throw Exception("AddCharge assumes singular MP");
754
+
755
+ // static Timer t("mptool AddCharge"); RegionTimer rg(t);
756
+
757
+ if (L2Norm(x) < 1e-10)
758
+ {
759
+ sh.Coef(0,0) += c * Complex(0,1)*kappa/sqrt(4*M_PI);
760
+ return;
761
+ }
762
+
763
+ // cout << "add charge, kappa rho = " << kappa*L2Norm(x) << ", order = " << sh.Order() << endl;
764
+
765
+ Vector<Complex> radial(sh.Order()+1);
766
+ Vector<Complex> sh_shapes(sqr (sh.Order()+1));
767
+
768
+ RADIAL::Eval(sh.Order(), kappa*L2Norm(x), 1.0/scale, radial);
769
+ // cout << "radial = " << radial << endl;
770
+ sh.Calc(x, sh_shapes);
771
+
772
+ for (int i = 0; i <= sh.Order(); i++)
773
+ {
774
+ IntRange r(sqr(i), sqr(i+1));
775
+ sh.Coefs().Range(r) += c * Complex(0,1)*kappa * radial(i).real()*Conj(sh_shapes.Range(r));
776
+ }
777
+ }
778
+
779
+
780
+ void AddDipole (Vec<3> x, Vec<3> d, Complex c)
781
+ {
782
+ // static Timer t("mptool AddDipole"); RegionTimer rg(t);
783
+ /*
784
+ double eps = 1e-4;
785
+ AddCharge(x+eps*d, -c/(2*eps));
786
+ AddCharge(x-eps*d, c/(2*eps));
787
+ return;
788
+ */
789
+
790
+ // book, formula (2.2.20)
791
+ if constexpr (!std::is_same<RADIAL,MPSingular>())
792
+ throw Exception("AddCharge assumes singular MP");
793
+
794
+ // dipole in origin:
795
+ MultiPole<MPSingular> tmp(1, kappa);
796
+ tmp.SH().Coef(1,1) += Complex(0,1)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(0)*c;
797
+ tmp.SH().Coef(1,-1) += Complex(0,1)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(0)*c;
798
+
799
+ tmp.SH().Coef(1,1) += Complex(1,0)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(1)*c;
800
+ tmp.SH().Coef(1,-1) -= Complex(1,0)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(1)*c;
801
+
802
+ tmp.SH().Coef(1,0) += -Complex(0,1)*kappa*kappa*sh.CalcAmn(0,0)/sqrt(4*M_PI) *d(2)*c;
803
+ tmp.TransformAdd (*this, -x);
804
+ }
805
+
806
+
807
+ void ChangeScaleTo (double newscale)
808
+ {
809
+ double fac = scale/newscale;
810
+ double prod = 1;
811
+ for (int n = 0; n <= sh.Order(); n++, prod*= fac)
812
+ sh.CoefsN(n) *= prod;
813
+ scale = newscale;
814
+ }
815
+
816
+ template <typename TARGET>
817
+ void Transform (MultiPole<TARGET> & target, Vec<3> dist) const
818
+ {
819
+ if (target.SH().Order() < 0) return;
820
+ if (SH().Order() < 0)
821
+ {
822
+ target.SH().Coefs() = 0.0;
823
+ return;
824
+ }
825
+
826
+ static Timer t("mptool Transform "+ToString(typeid(RADIAL).name())+ToString(typeid(TARGET).name()));
827
+ RegionTimer reg(t);
828
+
829
+ double len = L2Norm(dist);
830
+ double theta, phi;
831
+
832
+ if (len < 1e-30)
833
+ theta = 0;
834
+ else
835
+ theta = acos (dist(2) / len);
836
+
837
+ if (sqr(dist(0))+sqr(dist(1)) < 1e-30)
838
+ phi = 0;
839
+ else
840
+ phi = atan2(dist(1), dist(0));
841
+
842
+
843
+ MultiPole<RADIAL> tmp(*this);
844
+ tmp.SH().RotateZ(phi);
845
+ tmp.SH().RotateY(theta);
846
+
847
+ tmp.ShiftZ(-len, target);
848
+
849
+ target.SH().RotateY(-theta);
850
+ target.SH().RotateZ(-phi);
851
+ }
852
+
853
+ template <typename TARGET>
854
+ void TransformAdd (MultiPole<TARGET> & target, Vec<3> dist) const
855
+ {
856
+ if (SH().Order() < 0) return;
857
+ if (target.SH().Order() < 0) return;
858
+
859
+ MultiPole<TARGET> tmp{target};
860
+ Transform(tmp, dist);
861
+ target.SH().Coefs() += tmp.SH().Coefs();
862
+ }
863
+
864
+ #ifdef VER1
865
+ template <typename TARGET>
866
+ void ShiftZ (double z, MultiPole<TARGET> & target)
867
+ {
868
+ static Timer t("mptool ShiftZ"+ToString(typeid(RADIAL).name())+ToString(typeid(TARGET).name()));
869
+
870
+ RegionTimer rg(t);
871
+
872
+ int os = sh.Order();
873
+ int ot = target.SH().Order();
874
+
875
+ if (os > 100 && ot > 100 && abs(z)*kappa > 0.3*min(os,ot) && is_same<RADIAL,TARGET>())
876
+ {
877
+ MultiPole<TARGET> tmp {target};
878
+ ShiftZ(z/2, tmp);
879
+ tmp.ShiftZ(z/2, target);
880
+ return;
881
+ }
882
+
883
+
884
+ target.SH().Coefs()=0.0;
885
+
886
+ LocalHeap lh( 16*( (os+ot+1)*(os+1) + (os+1 + ot+1) ) + 8*2*(os+ot+1) + 500);
887
+
888
+ FlatMatrix<Complex> trafo(os+ot+1, os+1, lh);
889
+ FlatVector<Complex> hv1(os+1, lh), hv2(ot+1, lh);
890
+ FlatVector<double> amn(os+ot+1, lh);
891
+ FlatVector<double> inv_amn(os+ot+1, lh);
892
+
893
+ // trafo = Complex(0.0);
894
+
895
+
896
+ double tscale = target.Scale();
897
+ double inv_tscale = 1.0/tscale;
898
+
899
+
900
+ // (185) from paper 'fast, exact, stable, Gumerov+Duraiswami
901
+ // RADIAL::Eval(os+ot, kappa*abs(z), trafo.Col(0));
902
+ if (typeid(RADIAL) == typeid(TARGET))
903
+ SphericalBessel (os+ot, kappa*abs(z), tscale, trafo.Col(0));
904
+ else
905
+ SphericalHankel1 (os+ot, kappa*abs(z), inv_tscale, trafo.Col(0));
906
+
907
+ /*
908
+ if (L2Norm(trafo.Col(0)) > 1e5 || std::isnan(L2Norm(trafo.Col(0))))
909
+ {
910
+ *testout << "large Hankel: " << L2Norm(trafo.Col(0)) << endl;
911
+ *testout << "kappa z = " << kappa*z << ", os = " << os << ", ot = " << ot << endl;
912
+ }
913
+ */
914
+ // if (L2Norm(trafo.Col(0)) > 1e5)
915
+ // throw Exception ("z-shift - coefs large");
916
+
917
+ if (z < 0)
918
+ for (int l = 1; l < trafo.Height(); l+=2) trafo(l,0) *= -1;
919
+
920
+ for (int l = 0; l <= os+ot; l++)
921
+ trafo(l,0) *= sqrt(2*l+1);
922
+
923
+ if (os > 0)
924
+ {
925
+ for (int l = 1; l < os+ot; l++)
926
+ trafo(l,1) = -scale/sh.CalcAmn(0,0) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,0)
927
+ -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,0));
928
+ trafo(0,1) = -scale*tscale*trafo(1,0);
929
+ }
930
+
931
+ for (int n = 1; n < os; n++)
932
+ {
933
+ for (int l = 1; l < os+ot-n; l++)
934
+ trafo(l,n+1) = -scale/sh.CalcAmn(0,n) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,n)
935
+ -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,n)
936
+ -sh.CalcAmn(0,n-1)*scale*trafo(l,n-1));
937
+ trafo(0,n+1) = pow(-scale*tscale,n+1)*trafo(n+1,0);
938
+ }
939
+
940
+ cout << "m = " << 0 << endl
941
+ << trafo.Rows(0,ot+1) << endl;
942
+
943
+
944
+ for (int n = 0; n <= os; n++)
945
+ hv1(n) = sh.Coef(n,0);
946
+ hv2 = trafo.Rows(ot+1) * hv1;
947
+ for (int n = 0; n <= ot; n++)
948
+ target.SH().Coef(n,0) = hv2(n);
949
+
950
+
951
+ for (int m = 1; m <= min(os,ot); m++)
952
+ {
953
+ // fill recursive formula (187)
954
+ for (int l = m; l <= os+ot-m; l++)
955
+ trafo(l,m) = scale/sh.CalcBmn(-m, m) * (sh.CalcBmn(-m, l)*inv_tscale*trafo(l-1, m-1)
956
+ -sh.CalcBmn(m-1,l+1)*tscale*trafo(l+1,m-1));
957
+
958
+
959
+ /*
960
+ cout << "m = " << m << endl;
961
+ cout << " norm col0 = " << L2Norm(trafo.Col(m).Range(m,os+ot-m+1)) << endl;
962
+ */
963
+
964
+ for (int l = m-1; l < os+ot-m; l++)
965
+ {
966
+ amn(l) = sh.CalcAmn(m,l);
967
+ inv_amn(l) = scale/amn(l);
968
+ }
969
+
970
+ double prod = 1;
971
+ for (int n = m; n < os; n++)
972
+ {
973
+ for (int l = m+1; l < os+ot-n; l++)
974
+ trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
975
+ -amn(l-1)*inv_tscale*trafo(l-1,n)
976
+ -amn(n-1)*scale*trafo(l,n-1));
977
+
978
+ prod *= -scale*tscale;
979
+ trafo(m,n+1) = prod*trafo(n+1,m);
980
+ }
981
+
982
+ /*
983
+ cout << " norm trafo = "
984
+ << L2Norm(trafo.Rows(m,ot+1).Cols(m,os+1))
985
+ << " ortho " << L2Norm( Trans(trafo.Rows(m,ot+1).Cols(m,os+1))*trafo.Rows(m,ot+1).Cols(m,os+1)
986
+ - Identity(os+1-m)) << endl;
987
+ */
988
+ /*
989
+ *testout << "norm trafo = " << L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) << endl;
990
+ if ( L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) > 1e30)
991
+ {
992
+ *testout << trafo.Rows(m, ot+1).Cols(m,os+1) << endl;
993
+ for (int i = m; i < os+1; i++)
994
+ {
995
+ *testout << "norm col " << i << " = " << L2Norm(trafo.Col(i).Range(m,os+ot-i)) << endl;
996
+ *testout << "col " << i << " = " << trafo.Col(i).Range(m,os+ot-i) << endl;
997
+ }
998
+ throw Exception("large mat");
999
+ }
1000
+ */
1001
+
1002
+ cout << "m = " << m << endl
1003
+ << trafo.Rows(m,ot+1).Cols(m,os+1) << endl;
1004
+
1005
+ for (int n = m; n <= os; n++)
1006
+ hv1(n) = sh.Coef(n,m);
1007
+ hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1008
+ for (int n = m; n <= ot; n++)
1009
+ target.SH().Coef(n,m) = hv2(n);
1010
+
1011
+ for (int n = m; n <= os; n++)
1012
+ hv1(n) = sh.Coef(n,-m);
1013
+ hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1014
+ for (int n = m; n <= ot; n++)
1015
+ target.SH().Coef(n,-m) = hv2(n);
1016
+ }
1017
+ }
1018
+ #endif
1019
+
1020
+
1021
+ #ifdef VER2
1022
+
1023
+ template <typename TARGET>
1024
+ void ShiftZ (double z, MultiPole<TARGET> & target)
1025
+ {
1026
+ static Timer t("mptool ShiftZ"+ToString(typeid(RADIAL).name())+ToString(typeid(TARGET).name()));
1027
+ RegionTimer rg(t);
1028
+
1029
+ int os = sh.Order();
1030
+ int ot = target.SH().Order();
1031
+
1032
+ target.SH().Coefs()=0.0;
1033
+
1034
+ LocalHeap lh( 16*( (os+ot+1)*(os+1) + (os+1 + ot+1) ) + 8*2*(os+ot+1) + 500);
1035
+
1036
+ FlatMatrix<Complex> trafo(os+ot+1, os+1, lh);
1037
+ FlatVector<Complex> hv1(os+1, lh), hv2(ot+1, lh);
1038
+ FlatVector<double> amn(os+ot+1, lh);
1039
+ FlatVector<double> inv_amn(os+ot+1, lh);
1040
+
1041
+ // trafo = Complex(0.0);
1042
+
1043
+ double tscale = target.Scale();
1044
+ double inv_tscale = 1.0/tscale;
1045
+
1046
+
1047
+ // (185) from paper 'fast, exact, stable, Gumerov+Duraiswami
1048
+ // RADIAL::Eval(os+ot, kappa*abs(z), trafo.Col(0));
1049
+ if (typeid(RADIAL) == typeid(TARGET))
1050
+ SphericalBessel (os+ot, kappa*abs(z), tscale, trafo.Col(0));
1051
+ else
1052
+ SphericalHankel1 (os+ot, kappa*abs(z), inv_tscale, trafo.Col(0));
1053
+
1054
+ if (z < 0)
1055
+ for (int l = 1; l < trafo.Height(); l+=2) trafo(l,0) *= -1;
1056
+
1057
+ // for (int l = 0; l <= os+ot; l++)
1058
+ // trafo(l,0) *= sqrt(2*l+1);
1059
+
1060
+ if (os > 0)
1061
+ {
1062
+ for (int l = 1; l < os+ot; l++)
1063
+ {
1064
+ /*
1065
+ trafo(l,1) = -scale/sh.CalcAmn(0,0) *
1066
+ (sh.CalcAmn(0,l)*tscale*trafo(l+1,0)
1067
+ -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,0));
1068
+ */
1069
+
1070
+ int m = 0, n = 0;
1071
+ double fac = ((2*l+1.0)/(2*n+1.0));
1072
+ trafo(l,n+1) = -scale/ ( sqrt((n+1+m)*(n+1-m)) * fac) *
1073
+ (sqrt( (l+1+m)*(l+1-m)) * tscale * trafo(l+1,n)
1074
+ -sqrt( (l+m)*(l-m) ) * inv_tscale * trafo(l-1,n)
1075
+ -sqrt( (n+m)*(n-m) ) * fac * scale * trafo(l,n-1));
1076
+ }
1077
+ trafo(0,1) = -scale*tscale*trafo(1,0);
1078
+ }
1079
+
1080
+ for (int n = 1; n < os; n++)
1081
+ {
1082
+ for (int l = 1; l < os+ot-n; l++)
1083
+ {
1084
+ /*
1085
+ trafo(l,n+1) = -scale/sh.CalcAmn(0,n) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,n)
1086
+ -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,n)
1087
+ -sh.CalcAmn(0,n-1)*scale*trafo(l,n-1));
1088
+ */
1089
+
1090
+ int m = 0;
1091
+ double fac = ((2*l+1.0)/(2*n+1.0));
1092
+ trafo(l,n+1) = -scale / ( sqrt((n+1+m)*(n+1-m)) * fac) *
1093
+ (sqrt( (l+1+m)*(l+1-m)) * tscale * trafo(l+1,n)
1094
+ -sqrt( (l+m)*(l-m) ) * inv_tscale * trafo(l-1,n)
1095
+ -sqrt( (n+m)*(n-m) ) * fac * scale * trafo(l,n-1));
1096
+ }
1097
+ trafo(0,n+1) = pow(-scale*tscale,n+1)*trafo(n+1,0);
1098
+ }
1099
+
1100
+
1101
+ Matrix<Complex> scaledtrafo(os+ot+1, os+1);
1102
+ for (int l = 0; l <= os+ot; l++)
1103
+ for (int n = 0; n <= os; n++)
1104
+ scaledtrafo(l,n) = trafo(l,n) * sqrt( (2*l+1)*(2*n+1) );
1105
+
1106
+ // cout << "m = " << 0 << endl
1107
+ // << scaledtrafo.Rows(0,ot+1) << endl;
1108
+
1109
+ for (int n = 0; n <= os; n++)
1110
+ hv1(n) = sh.Coef(n,0) * sqrt(2*n+1);
1111
+ hv2 = trafo.Rows(ot+1) * hv1;
1112
+ for (int n = 0; n <= ot; n++)
1113
+ target.SH().Coef(n,0) = hv2(n) * sqrt(2*n+1);
1114
+
1115
+
1116
+ for (int m = 1; m <= min(os,ot); m++)
1117
+ {
1118
+ // fill recursive formula (187)
1119
+ for (int l = m; l <= os+ot-m; l++)
1120
+ {
1121
+ trafo(l,m) = scale/sh.CalcBmn(-m, m) *
1122
+ (sh.CalcBmn(-m, l)*inv_tscale * trafo(l-1, m-1) * sqrt( (2*l-1)*(2*m-1) )
1123
+ -sh.CalcBmn(m-1,l+1)*tscale * trafo(l+1,m-1) * sqrt( (2*l+3)*(2*m-1)) );
1124
+ trafo(l,m) /= sqrt( (2*l+1)*(2*m+1) );
1125
+ }
1126
+
1127
+ cout << "m = " << m << endl;
1128
+ cout << " norm col0 = " << L2Norm(trafo.Col(m).Range(m,os+ot-m+1)) << endl;
1129
+
1130
+ for (int l = m-1; l < os+ot-m; l++)
1131
+ {
1132
+ amn(l) = sh.CalcAmn(m,l);
1133
+ inv_amn(l) = scale/amn(l);
1134
+ }
1135
+
1136
+ double prod = 1;
1137
+ for (int n = m; n < os; n++)
1138
+ {
1139
+ for (int l = m+1; l < os+ot-n; l++)
1140
+ {
1141
+ /*
1142
+ trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
1143
+ -amn(l-1)*inv_tscale*trafo(l-1,n)
1144
+ -amn(n-1)*scale*trafo(l,n-1));
1145
+ */
1146
+
1147
+
1148
+ double fac = ((2*l+1.0)/(2*n+1.0));
1149
+ trafo(l,n+1) = -scale / ( sqrt((n+1+m)*(n+1-m)) * fac) *
1150
+ (sqrt( (l+1+m)*(l+1-m)) * tscale * trafo(l+1,n)
1151
+ -sqrt( (l+m)*(l-m) ) * inv_tscale * trafo(l-1,n)
1152
+ -sqrt( (n+m)*(n-m) ) * fac * scale * trafo(l,n-1));
1153
+ }
1154
+ prod *= -scale*tscale;
1155
+ trafo(m,n+1) = prod*trafo(n+1,m);
1156
+ }
1157
+
1158
+ double normleft = 0;
1159
+ for (int l = m; l <= ot; l++)
1160
+ for (int n = m; n <= min(l,os); n++)
1161
+ normleft += sqr(abs(trafo(l,n)));
1162
+ normleft = sqrt(normleft);
1163
+ cout << " norm trafo = "
1164
+ << L2Norm(trafo.Rows(m,ot+1).Cols(m,os+1)) << ", normleft = " << normleft << endl;
1165
+
1166
+ // << " ortho " << L2Norm( Trans(trafo.Rows(m,ot+1).Cols(m,os+1))*trafo.Rows(m,ot+1).Cols(m,os+1)
1167
+ // - Identity(os+1-m)) << endl;
1168
+ /*
1169
+ *testout << "norm trafo = " << L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) << endl;
1170
+ if ( L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) > 1e30)
1171
+ {
1172
+ *testout << trafo.Rows(m, ot+1).Cols(m,os+1) << endl;
1173
+ for (int i = m; i < os+1; i++)
1174
+ {
1175
+ *testout << "norm col " << i << " = " << L2Norm(trafo.Col(i).Range(m,os+ot-i)) << endl;
1176
+ *testout << "col " << i << " = " << trafo.Col(i).Range(m,os+ot-i) << endl;
1177
+ }
1178
+ throw Exception("large mat");
1179
+ }
1180
+ */
1181
+
1182
+
1183
+ /*
1184
+ Matrix<Complex> scaledtrafo(os+ot+1, os+1);
1185
+ for (int l = 0; l <= os+ot; l++)
1186
+ for (int n = 0; n <= os; n++)
1187
+ scaledtrafo(l,n) = trafo(l,n) * sqrt( (2*l+1)*(2*n+1) );
1188
+
1189
+ cout << "m = " << m << endl
1190
+ << scaledtrafo.Rows(m,ot+1).Cols(m,os+1) << endl;
1191
+ */
1192
+
1193
+ for (int n = m; n <= os; n++)
1194
+ hv1(n) = sh.Coef(n,m) * sqrt(2*n+1);
1195
+ hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1196
+ for (int n = m; n <= ot; n++)
1197
+ target.SH().Coef(n,m) = hv2(n)*sqrt(2*n+1);
1198
+
1199
+ for (int n = m; n <= os; n++)
1200
+ hv1(n) = sh.Coef(n,-m) * sqrt(2*n+1);
1201
+ hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1202
+ for (int n = m; n <= ot; n++)
1203
+ target.SH().Coef(n,-m) = hv2(n) * sqrt(2*n+1);
1204
+ }
1205
+ }
1206
+ #endif
1207
+
1208
+
1209
+
1210
+
1211
+ template <typename TARGET>
1212
+ void ShiftZ (double z, MultiPole<TARGET> & target)
1213
+ {
1214
+ static Timer t("mptool ShiftZ"+ToString(typeid(RADIAL).name())+ToString(typeid(TARGET).name()));
1215
+ RegionTimer rg(t);
1216
+
1217
+ int os = sh.Order();
1218
+ int ot = target.SH().Order();
1219
+
1220
+ target.SH().Coefs()=0.0;
1221
+
1222
+ LocalHeap lh( 32*( (os+ot+1)*(os+ot+1) + (os+1 + ot+1) ) + 8*3*(os+ot+1) + 500);
1223
+
1224
+ FlatMatrix<Complex> trafo(os+ot+1, max(os,ot)+1, lh);
1225
+ FlatMatrix<Complex> oldtrafo(os+ot+1, max(os,ot)+1, lh);
1226
+ FlatVector<Complex> hv1(os+1, lh), hv2(ot+1, lh);
1227
+
1228
+ // trafo = Complex(0.0);
1229
+
1230
+ double tscale = target.Scale();
1231
+ double inv_tscale = 1.0/tscale;
1232
+
1233
+ FlatVector<double> amn(os+ot+1, lh);
1234
+ FlatVector<double> inv_amn(os+ot+1, lh);
1235
+
1236
+ FlatVector<double> powscale(os+1, lh);
1237
+ double prod = 1;
1238
+ for (int i = 0; i <= os; i++)
1239
+ {
1240
+ powscale(i) = prod;
1241
+ prod *= -scale*tscale;
1242
+ }
1243
+
1244
+ // (185) from paper 'fast, exact, stable, Gumerov+Duraiswami
1245
+ // RADIAL::Eval(os+ot, kappa*abs(z), trafo.Col(0));
1246
+ if (typeid(RADIAL) == typeid(TARGET))
1247
+ SphericalBessel (os+ot, kappa*abs(z), tscale, trafo.Col(0));
1248
+ else
1249
+ SphericalHankel1 (os+ot, kappa*abs(z), inv_tscale, trafo.Col(0));
1250
+
1251
+ if (z < 0)
1252
+ for (int l = 1; l < trafo.Height(); l+=2) trafo(l,0) *= -1;
1253
+
1254
+ for (int l = 0; l <= os+ot; l++)
1255
+ trafo(l,0) *= sqrt(2*l+1);
1256
+
1257
+ // for (int l = 0; l <= os+ot; l++)
1258
+ // trafo(l,0) *= sqrt(2*l+1);
1259
+
1260
+ if (os > 0)
1261
+ {
1262
+ for (int l = 1; l < os+ot; l++)
1263
+ trafo(l,1) = -scale/sh.CalcAmn(0,0) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,0)
1264
+ -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,0));
1265
+ trafo(0,1) = -scale*tscale*trafo(1,0);
1266
+ }
1267
+
1268
+ for (int n = 1; n < trafo.Width()-1; n++)
1269
+ {
1270
+ for (int l = 1; l < os+ot-n; l++)
1271
+ trafo(l,n+1) = -scale/sh.CalcAmn(0,n) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,n)
1272
+ -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,n)
1273
+ -sh.CalcAmn(0,n-1)*scale*trafo(l,n-1));
1274
+ trafo(0,n+1) = pow(-scale*tscale,n+1)*trafo(n+1,0);
1275
+ }
1276
+
1277
+ for (int n = 0; n <= os; n++)
1278
+ hv1(n) = sh.Coef(n,0);
1279
+ hv2 = trafo.Rows(ot+1).Cols(os+1) * hv1;
1280
+ for (int n = 0; n <= ot; n++)
1281
+ target.SH().Coef(n,0) = hv2(n);
1282
+
1283
+
1284
+ for (int m = 1; m <= min(os,ot); m++)
1285
+ {
1286
+
1287
+
1288
+ for (int l = m-1; l < os+ot-m; l++)
1289
+ {
1290
+ amn(l) = sh.CalcAmn(m,l);
1291
+ inv_amn(l) = scale/amn(l);
1292
+ }
1293
+
1294
+ if (typeid(RADIAL) != typeid(TARGET))
1295
+
1296
+ {
1297
+ // fill recursive formula (187)
1298
+ for (int l = m; l <= os+ot-m; l++)
1299
+ trafo(l,m) = scale/sh.CalcBmn(-m, m) * (sh.CalcBmn(-m, l)*inv_tscale*trafo(l-1, m-1)
1300
+ -sh.CalcBmn(m-1,l+1)*tscale*trafo(l+1,m-1));
1301
+
1302
+ for (int n = m; n < os; n++)
1303
+ {
1304
+ for (int l = n+1; l < os+ot-n; l++)
1305
+ trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
1306
+ -amn(l-1)*inv_tscale*trafo(l-1,n)
1307
+ -amn(n-1)*scale*trafo(l,n-1));
1308
+ }
1309
+ }
1310
+
1311
+ else
1312
+
1313
+ {
1314
+ /*
1315
+ for (int n = m; n < trafo.Width()-1; n++)
1316
+ {
1317
+ for (int l = n+1; l < os+ot-n; l++)
1318
+ trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
1319
+ -amn(l-1)*inv_tscale*trafo(l-1,n)
1320
+ -amn(n-1)*scale*trafo(l,n-1));
1321
+ }
1322
+ */
1323
+
1324
+ trafo.Swap (oldtrafo);
1325
+ trafo = 0.0;
1326
+
1327
+ // fill recursive formula (187)
1328
+ for (int l = m; l <= os+ot-m; l++)
1329
+ trafo(l,m) = scale/sh.CalcBmn(-m, m) * (sh.CalcBmn(-m, l)*inv_tscale*oldtrafo(l-1, m-1)
1330
+ -sh.CalcBmn(m-1,l+1)*tscale*oldtrafo(l+1,m-1));
1331
+
1332
+ for (int n = m; n < trafo.Width()-1; n++)
1333
+ {
1334
+ // int l = 2*order-n-1;
1335
+ int l = trafo.Height()-n-2;
1336
+
1337
+ trafo(l,n+1) = scale/sh.CalcBmn(-m,n+1)* (sh.CalcBmn(m-1,n) * scale*trafo(l,n-1)
1338
+ - sh.CalcBmn(m-1,l+1)*tscale*oldtrafo(l+1,n)
1339
+ + sh.CalcBmn(-m,l) * 1/tscale*oldtrafo(l-1,n) );
1340
+
1341
+ trafo(l-1,n) = tscale/amn(l-1) * (amn(l) * tscale*trafo(l+1,n)
1342
+ - amn(n-1)* scale*trafo(l,n-1)
1343
+ + amn(n)* 1/scale*trafo(l,n+1));
1344
+ }
1345
+
1346
+ // the same thing 1 row up
1347
+ for (int n = m; n < trafo.Width()-2; n++)
1348
+ {
1349
+ // int l = 2*order-n-2;
1350
+ int l = trafo.Height()-n-3;
1351
+
1352
+ trafo(l,n+1) = scale/sh.CalcBmn(-m,n+1)* (sh.CalcBmn(m-1,n) * scale*trafo(l,n-1)
1353
+ - sh.CalcBmn(m-1,l+1) * tscale* oldtrafo(l+1,n)
1354
+ + sh.CalcBmn(-m,l) * 1/tscale* oldtrafo(l-1,n) );
1355
+
1356
+ trafo(l-1,n) = tscale/amn(l-1) * (amn(l) * tscale*trafo(l+1,n)
1357
+ -amn(n-1)* scale*trafo(l,n-1) +
1358
+ amn(n) * 1/scale*trafo(l,n+1)) ;
1359
+ }
1360
+
1361
+
1362
+ // for (int l = 2*order; l >= m; l--)
1363
+ // for (int n = m+1; n < min(2*order-l,l); n++)
1364
+ for (int l = trafo.Height()-1; l >= m; l--)
1365
+ for (int n = m+1; n < min<int>(trafo.Height()-1-l,l); n++)
1366
+ {
1367
+ trafo(l-1,n) = tscale/amn(l-1)* ( amn(l) * tscale*trafo(l+1,n)
1368
+ -amn(n-1)* scale*trafo(l,n-1)
1369
+ +amn(n) * 1/scale*trafo(l,n+1)) ;
1370
+ }
1371
+ }
1372
+
1373
+
1374
+ /*
1375
+ cout << "m = " << m << endl
1376
+ << trafo << endl;
1377
+ */
1378
+ for (int n = m; n < os; n++)
1379
+ for (int l = n+1; l <= os; l++)
1380
+ trafo(n,l) = powscale(l-n) * trafo(l,n);
1381
+ // trafo(n,l) = pow(-scale*tscale, l-n) * trafo(l,n);
1382
+
1383
+ /*
1384
+ cout << " norm trafo = "
1385
+ << L2Norm(trafo.Rows(m,ot+1).Cols(m,os+1)) << endl;
1386
+ */
1387
+
1388
+ for (int n = m; n <= os; n++)
1389
+ hv1(n) = sh.Coef(n,m);
1390
+ hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1391
+ for (int n = m; n <= ot; n++)
1392
+ target.SH().Coef(n,m) = hv2(n);
1393
+
1394
+ for (int n = m; n <= os; n++)
1395
+ hv1(n) = sh.Coef(n,-m);
1396
+ hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1397
+ for (int n = m; n <= ot; n++)
1398
+ target.SH().Coef(n,-m) = hv2(n);
1399
+ }
1400
+ }
1401
+
1402
+
1403
+
1404
+
1405
+
1406
+
1407
+ };
1408
+
1409
+
1410
+
1411
+ // ***************** parameters ****************
1412
+
1413
+ static int MPOrder (double rho_kappa)
1414
+ {
1415
+ return max (20, int(2*rho_kappa));
1416
+ }
1417
+ static constexpr int maxdirect = 100;
1418
+
1419
+ class SingularMLMultiPole
1420
+ {
1421
+ static Array<size_t> nodes_on_level;
1422
+
1423
+ struct Node
1424
+ {
1425
+ Vec<3> center;
1426
+ double r;
1427
+ int level;
1428
+ std::array<unique_ptr<Node>,8> childs;
1429
+ MultiPole<MPSingular> mp;
1430
+
1431
+ Array<tuple<Vec<3>, Complex>> charges;
1432
+ Array<tuple<Vec<3>, Vec<3>, Complex>> dipoles;
1433
+ int total_sources;
1434
+
1435
+ Node (Vec<3> acenter, double ar, int alevel, int order, double kappa)
1436
+ : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, min(1.0, 1*r*kappa))
1437
+ // : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, 1.0)
1438
+ {
1439
+ // cout << "singml, add node, level = " << level << endl;
1440
+ if (level < nodes_on_level.Size())
1441
+ nodes_on_level[level]++;
1442
+ }
1443
+
1444
+
1445
+ void CreateChilds()
1446
+ {
1447
+ if (childs[0]) throw Exception("have already childs");
1448
+ for (int i = 0; i < 8; i++)
1449
+ {
1450
+ Vec<3> cc = center;
1451
+ cc(0) += (i&1) ? r/2 : -r/2;
1452
+ cc(1) += (i&2) ? r/2 : -r/2;
1453
+ cc(2) += (i&4) ? r/2 : -r/2;
1454
+ childs[i] = make_unique<Node> (cc, r/2, level+1, max(mp.SH().Order()/2, 8), mp.Kappa());
1455
+ }
1456
+ }
1457
+
1458
+
1459
+ void AddCharge (Vec<3> x, Complex c)
1460
+ {
1461
+ if (childs[0])
1462
+ {
1463
+ // directly send to childs:
1464
+ int childnum = 0;
1465
+ if (x(0) > center(0)) childnum += 1;
1466
+ if (x(1) > center(1)) childnum += 2;
1467
+ if (x(2) > center(2)) childnum += 4;
1468
+ childs[childnum] -> AddCharge(x, c);
1469
+ return;
1470
+ }
1471
+
1472
+ charges.Append( tuple{x,c} );
1473
+
1474
+ if (r*mp.Kappa() < 1e-8) return;
1475
+ if (charges.Size() < maxdirect && r*mp.Kappa() < 1)
1476
+ return;
1477
+
1478
+ CreateChilds();
1479
+
1480
+ for (auto [x,c] : charges)
1481
+ AddCharge (x,c);
1482
+ for (auto [x,d,c] : dipoles)
1483
+ AddDipole (x,d,c);
1484
+
1485
+ charges.SetSize0();
1486
+ dipoles.SetSize0();
1487
+ }
1488
+
1489
+
1490
+ void AddDipole (Vec<3> x, Vec<3> d, Complex c)
1491
+ {
1492
+ if (childs[0])
1493
+ {
1494
+ // directly send to childs:
1495
+
1496
+ int childnum = 0;
1497
+ if (x(0) > center(0)) childnum += 1;
1498
+ if (x(1) > center(1)) childnum += 2;
1499
+ if (x(2) > center(2)) childnum += 4;
1500
+ childs[childnum] -> AddDipole(x, d, c);
1501
+ return;
1502
+ }
1503
+
1504
+ dipoles.Append (tuple{x,d,c});
1505
+
1506
+ if (dipoles.Size() < maxdirect || r < 1e-8)
1507
+ return;
1508
+
1509
+ CreateChilds();
1510
+
1511
+ for (auto [x,c] : charges)
1512
+ AddCharge (x,c);
1513
+ for (auto [x,d,c] : dipoles)
1514
+ AddDipole (x,d,c);
1515
+
1516
+ charges.SetSize0();
1517
+ dipoles.SetSize0();
1518
+ }
1519
+
1520
+
1521
+ Complex Evaluate(Vec<3> p) const
1522
+ {
1523
+ Complex sum = 0;
1524
+ if (childs[0])
1525
+ {
1526
+ for (auto & child : childs)
1527
+ sum += child->Evaluate(p);
1528
+ return sum;
1529
+ }
1530
+
1531
+ for (auto [x,c] : charges)
1532
+ if (double rho = L2Norm(p-x); rho > 0)
1533
+ sum += c*(1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) / rho;
1534
+
1535
+ for (auto [x,d,c] : dipoles)
1536
+ if (double rho = L2Norm(p-x); rho > 0)
1537
+ {
1538
+ Vec<3> drhodp = 1.0/rho * (p-x);
1539
+ Complex dGdrho = c*(1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
1540
+ (Complex(0, mp.Kappa())/rho - 1.0/sqr(rho));
1541
+ sum += dGdrho * InnerProduct(drhodp, d);
1542
+ }
1543
+
1544
+ return sum;
1545
+ }
1546
+
1547
+ void CalcTotalSources()
1548
+ {
1549
+ total_sources = charges.Size() + dipoles.Size();
1550
+ for (auto & child : childs)
1551
+ if (child)
1552
+ {
1553
+ child->CalcTotalSources();
1554
+ total_sources += child->total_sources;
1555
+ }
1556
+ }
1557
+
1558
+ void CalcMP()
1559
+ {
1560
+ mp.SH().Coefs() = 0.0;
1561
+ if (childs[0])
1562
+ {
1563
+ if (total_sources < 1000)
1564
+ for (auto & child : childs)
1565
+ child->CalcMP();
1566
+ else
1567
+ ParallelFor (8, [&] (int nr)
1568
+ {
1569
+ childs[nr] -> CalcMP();
1570
+ });
1571
+
1572
+
1573
+ for (auto & child : childs)
1574
+ child->mp.TransformAdd(mp, center-child->center);
1575
+ }
1576
+ else
1577
+ {
1578
+ if (charges.Size()+dipoles.Size() == 0)
1579
+ {
1580
+ mp = MultiPole<MPSingular> (-1, mp.Kappa());
1581
+ return;
1582
+ }
1583
+
1584
+ for (auto [x,c] : charges)
1585
+ mp.AddCharge (x-center,c);
1586
+
1587
+ for (auto [x,d,c] : dipoles)
1588
+ mp.AddDipole (x-center, d, c);
1589
+ }
1590
+ }
1591
+
1592
+ Complex EvaluateMP(Vec<3> p) const
1593
+ {
1594
+ if (charges.Size() || dipoles.Size())
1595
+ return Evaluate(p);
1596
+
1597
+ if (L2Norm(p-center) > 3*r)
1598
+ return mp.Eval(p-center);
1599
+
1600
+ if (!childs[0]) // || level==1)
1601
+ return Evaluate(p);
1602
+
1603
+ Complex sum = 0.0;
1604
+ for (auto & child : childs)
1605
+ sum += child->EvaluateMP(p);
1606
+ return sum;
1607
+ }
1608
+
1609
+
1610
+ void Print (ostream & ost) const
1611
+ {
1612
+ ost << "c = " << center << ", r = " << r << endl;
1613
+ // for (int i = 0; i < loc_pnts.Size(); i++)
1614
+ for (auto [x,c] : charges)
1615
+ ost << "xi = " << x << ", ci = " << c << endl;
1616
+
1617
+ for (int i = 0; i < 8; i++)
1618
+ if (childs[i]) childs[i] -> Print (ost);
1619
+ }
1620
+
1621
+ double Norm () const
1622
+ {
1623
+ double norm = L2Norm(mp.SH().Coefs());
1624
+ if (childs[0])
1625
+ for (auto & ch : childs)
1626
+ norm += ch->Norm();
1627
+ return norm;
1628
+ }
1629
+
1630
+ size_t NumCoefficients() const
1631
+ {
1632
+ size_t num = sqr(mp.SH().Order()+1);
1633
+ if (childs[0])
1634
+ for (auto & ch : childs)
1635
+ num += ch->NumCoefficients();
1636
+ return num;
1637
+ }
1638
+ };
1639
+
1640
+ Node root;
1641
+ bool havemp = false;
1642
+
1643
+ public:
1644
+ SingularMLMultiPole (Vec<3> center, double r, int order, double kappa)
1645
+ : root(center, r, 0, order, kappa)
1646
+ {
1647
+ nodes_on_level = 0;
1648
+ nodes_on_level[0] = 1;
1649
+ }
1650
+
1651
+ double Kappa() const { return root.mp.Kappa(); }
1652
+
1653
+ void AddCharge(Vec<3> x, Complex c)
1654
+ {
1655
+ root.AddCharge(x, c);
1656
+ }
1657
+
1658
+ void AddDipole(Vec<3> x, Vec<3> d, Complex c)
1659
+ {
1660
+ root.AddDipole(x, d, c);
1661
+ }
1662
+
1663
+ void Print (ostream & ost) const
1664
+ {
1665
+ root.Print(ost);
1666
+ }
1667
+
1668
+ double Norm() const
1669
+ {
1670
+ return root.Norm();
1671
+ }
1672
+
1673
+ size_t NumCoefficients() const
1674
+ {
1675
+ return root.NumCoefficients();
1676
+ }
1677
+
1678
+ void CalcMP()
1679
+ {
1680
+ static Timer t("mptool compute singular MLMP"); RegionTimer rg(t);
1681
+
1682
+ /*
1683
+ int maxlevel = 0;
1684
+ for (auto [i,num] : Enumerate(nodes_on_level))
1685
+ if (num > 0) maxlevel = i;
1686
+
1687
+ for (int i = 0; i <= maxlevel; i++)
1688
+ cout << "sing " << i << ": " << nodes_on_level[i] << endl;
1689
+ */
1690
+ root.CalcTotalSources();
1691
+ root.CalcMP();
1692
+
1693
+ havemp = true;
1694
+ }
1695
+
1696
+ Complex Evaluate (Vec<3> p) const
1697
+ {
1698
+ if (havemp)
1699
+ return root.EvaluateMP(p);
1700
+ else
1701
+ return root.Evaluate(p);
1702
+ }
1703
+
1704
+ friend class RegularMLMultiPole;
1705
+ };
1706
+
1707
+
1708
+ inline ostream & operator<< (ostream & ost, const SingularMLMultiPole & mlmp)
1709
+ {
1710
+ mlmp.Print(ost);
1711
+ return ost;
1712
+ }
1713
+
1714
+
1715
+ class RegularMLMultiPole
1716
+ {
1717
+ static Array<size_t> nodes_on_level;
1718
+
1719
+ struct Node
1720
+ {
1721
+ Vec<3> center;
1722
+ double r;
1723
+ int level;
1724
+ std::array<unique_ptr<Node>,8> childs;
1725
+ MultiPole<MPRegular> mp;
1726
+ Array<Vec<3>> targets;
1727
+ int total_targets;
1728
+
1729
+ Array<const SingularMLMultiPole::Node*> singnodes;
1730
+
1731
+ Node (Vec<3> acenter, double ar, int alevel, int order, double kappa)
1732
+ : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, 1.0/min(1.0, 0.25*r*kappa))
1733
+ // : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, 1.0)
1734
+ {
1735
+ if (level < nodes_on_level.Size())
1736
+ nodes_on_level[level]++;
1737
+ }
1738
+
1739
+
1740
+ void CreateChilds()
1741
+ {
1742
+ if (childs[0]) throw Exception("have already childs");
1743
+ // create children nodes:
1744
+ for (int i = 0; i < 8; i++)
1745
+ {
1746
+ Vec<3> cc = center;
1747
+ cc(0) += (i&1) ? r/2 : -r/2;
1748
+ cc(1) += (i&2) ? r/2 : -r/2;
1749
+ cc(2) += (i&4) ? r/2 : -r/2;
1750
+ childs[i] = make_unique<Node> (cc, r/2, level+1, max(mp.SH().Order()/2, 8), mp.Kappa());
1751
+ }
1752
+ }
1753
+
1754
+ void AddSingularNode (const SingularMLMultiPole::Node & singnode, bool allow_refine)
1755
+ {
1756
+ if (mp.SH().Order() < 0) return;
1757
+ if (singnode.mp.SH().Order() < 0) return;
1758
+ if (L2Norm(singnode.mp.SH().Coefs()) == 0) return;
1759
+ if (level > 20)
1760
+ {
1761
+ singnodes.Append(&singnode);
1762
+ return;
1763
+ }
1764
+
1765
+ // static Timer t("AddSingularNode"); RegionTimer reg(t);
1766
+
1767
+ Vec<3> dist = center-singnode.center;
1768
+
1769
+ // if (L2Norm(dist)*mp.Kappa() > (mp.Order()+singnode.mp.Order()))
1770
+ if (L2Norm(dist) > 2*(r + singnode.r))
1771
+ {
1772
+ if (singnode.mp.Order() > 2 * mp.Order() &&
1773
+ singnode.childs[0] &&
1774
+ singnode.childs[0]->mp.Order() < singnode.mp.Order())
1775
+ {
1776
+ for (auto & child : singnode.childs)
1777
+ AddSingularNode (*child, allow_refine);
1778
+ return;
1779
+ }
1780
+
1781
+ // static Timer t("mptool transform Helmholtz-criterion"); RegionTimer r(t);
1782
+ singnode.mp.TransformAdd(mp, dist);
1783
+ return;
1784
+ }
1785
+
1786
+
1787
+ if ( singnode.childs[0]==nullptr )
1788
+ {
1789
+ singnodes.Append(&singnode);
1790
+ return;
1791
+ }
1792
+
1793
+ if (r > singnode.r)
1794
+ {
1795
+ if (allow_refine)
1796
+ {
1797
+ if (!childs[0])
1798
+ CreateChilds();
1799
+
1800
+ for (auto & ch : childs)
1801
+ ch -> AddSingularNode (singnode, allow_refine);
1802
+ }
1803
+ else
1804
+ {
1805
+ if (total_targets < 1000)
1806
+ {
1807
+ for (auto & ch : childs)
1808
+ if (ch)
1809
+ ch -> AddSingularNode (singnode, allow_refine);
1810
+ }
1811
+ else
1812
+ ParallelFor (8, [&] (int nr)
1813
+ {
1814
+ if (childs[nr])
1815
+ childs[nr] -> AddSingularNode (singnode, allow_refine);
1816
+ });
1817
+
1818
+ if (targets.Size())
1819
+ singnodes.Append(&singnode);
1820
+ }
1821
+ }
1822
+ else
1823
+ {
1824
+ for (auto & childsing : singnode.childs)
1825
+ AddSingularNode (*childsing, allow_refine);
1826
+ }
1827
+ }
1828
+
1829
+ void LocalizeExpansion(bool allow_refine)
1830
+ {
1831
+ if (allow_refine)
1832
+ if (mp.Order() > 20 && !childs[0])
1833
+ CreateChilds();
1834
+
1835
+ if (childs[0])
1836
+ {
1837
+ for (auto & ch : childs)
1838
+ {
1839
+ if (L2Norm(mp.SH().Coefs()) > 0)
1840
+ mp.TransformAdd (ch->mp, ch->center-center);
1841
+ ch->LocalizeExpansion(allow_refine);
1842
+ }
1843
+ mp = MultiPole<MPRegular>(-1, mp.Kappa());
1844
+ //mp.SH().Coefs()=0.0;
1845
+ }
1846
+ }
1847
+
1848
+ Complex Evaluate (Vec<3> p) const
1849
+ {
1850
+ // *testout << "eval p = " << p << ", level = " << level << ", center = " << center << ", r = " << r << endl;
1851
+ Complex sum = 0.0;
1852
+ /*
1853
+ if (childs[0])
1854
+ {
1855
+ int childnum = 0;
1856
+ if (p(0) > center(0)) childnum += 1;
1857
+ if (p(1) > center(1)) childnum += 2;
1858
+ if (p(2) > center(2)) childnum += 4;
1859
+ sum = childs[childnum]->Evaluate(p);
1860
+ }
1861
+ */
1862
+ int childnum = 0;
1863
+ if (p(0) > center(0)) childnum += 1;
1864
+ if (p(1) > center(1)) childnum += 2;
1865
+ if (p(2) > center(2)) childnum += 4;
1866
+ if (childs[childnum])
1867
+ sum = childs[childnum]->Evaluate(p);
1868
+ else
1869
+ sum = mp.Eval(p-center);
1870
+
1871
+
1872
+ static Timer t("mptool direct evaluate"); RegionTimer r(t);
1873
+ for (auto sn : singnodes)
1874
+ sum += sn->EvaluateMP(p);
1875
+
1876
+ return sum;
1877
+ }
1878
+
1879
+ double Norm() const
1880
+ {
1881
+ double norm = L2Norm(mp.SH().Coefs());
1882
+ if (childs[0])
1883
+ for (auto & ch : childs)
1884
+ norm += ch->Norm();
1885
+ return norm;
1886
+ }
1887
+
1888
+ size_t NumCoefficients() const
1889
+ {
1890
+ size_t num = sqr(mp.SH().Order()+1);
1891
+ if (childs[0])
1892
+ for (auto & ch : childs)
1893
+ num += ch->NumCoefficients();
1894
+ return num;
1895
+ }
1896
+
1897
+ void AddTarget (Vec<3> x)
1898
+ {
1899
+ if (childs[0])
1900
+ {
1901
+ // directly send to childs:
1902
+ int childnum = 0;
1903
+ if (x(0) > center(0)) childnum += 1;
1904
+ if (x(1) > center(1)) childnum += 2;
1905
+ if (x(2) > center(2)) childnum += 4;
1906
+ childs[childnum] -> AddTarget( x );
1907
+ return;
1908
+ }
1909
+
1910
+ targets.Append( x );
1911
+
1912
+ if (r*mp.Kappa() < 1e-8) return;
1913
+ if (targets.Size() < maxdirect && r*mp.Kappa() < 1)
1914
+ return;
1915
+
1916
+ CreateChilds();
1917
+
1918
+ for (auto t : targets)
1919
+ AddTarget (t);
1920
+ targets.SetSize0();
1921
+ }
1922
+
1923
+ void CalcTotalTargets()
1924
+ {
1925
+ total_targets = targets.Size();
1926
+ for (auto & child : childs)
1927
+ if (child)
1928
+ {
1929
+ child->CalcTotalTargets();
1930
+ total_targets += child->total_targets;
1931
+ }
1932
+ }
1933
+
1934
+ void RemoveEmptyTrees()
1935
+ {
1936
+ for (auto & child : childs)
1937
+ if (child)
1938
+ {
1939
+ child->RemoveEmptyTrees();
1940
+ // if (child->total_targets == 0)
1941
+ // child = nullptr;
1942
+ }
1943
+
1944
+ if (total_targets == 0)
1945
+ mp = MultiPole<MPRegular>(-1, mp.Kappa());
1946
+ }
1947
+
1948
+ };
1949
+
1950
+ Node root;
1951
+ shared_ptr<SingularMLMultiPole> singmp;
1952
+
1953
+ public:
1954
+ RegularMLMultiPole (shared_ptr<SingularMLMultiPole> asingmp, Vec<3> center, double r, int order)
1955
+ : root(center, r, 0, order, asingmp->Kappa()), singmp(asingmp)
1956
+ {
1957
+ if (!singmp->havemp) throw Exception("first call Calc for singular MP");
1958
+
1959
+ nodes_on_level = 0;
1960
+ nodes_on_level[0] = 1;
1961
+ {
1962
+ static Timer t("mptool compute regular MLMP"); RegionTimer rg(t);
1963
+ root.AddSingularNode(singmp->root, true);
1964
+ // cout << "norm after S->R conversion: " << root.Norm() << endl;
1965
+ }
1966
+
1967
+
1968
+ /*
1969
+ int maxlevel = 0;
1970
+ for (auto [i,num] : Enumerate(nodes_on_level))
1971
+ if (num > 0) maxlevel = i;
1972
+
1973
+ for (int i = 0; i <= maxlevel; i++)
1974
+ cout << "reg " << i << ": " << nodes_on_level[i] << endl;
1975
+ */
1976
+
1977
+ {
1978
+ static Timer t("mptool expand regular MLMP"); RegionTimer rg(t);
1979
+ root.LocalizeExpansion(true);
1980
+ // cout << "norm after local expansion: " << root.Norm() << endl;
1981
+ }
1982
+ }
1983
+
1984
+ RegularMLMultiPole (Vec<3> center, double r, int order, double kappa)
1985
+ : root(center, r, 0, order, kappa)
1986
+ {
1987
+ nodes_on_level = 0;
1988
+ nodes_on_level[0] = 1;
1989
+ }
1990
+
1991
+ void AddTarget (Vec<3> t)
1992
+ {
1993
+ root.AddTarget (t);
1994
+ }
1995
+
1996
+ void CalcMP(shared_ptr<SingularMLMultiPole> asingmp)
1997
+ {
1998
+ singmp = asingmp;
1999
+
2000
+ root.CalcTotalTargets();
2001
+ root.RemoveEmptyTrees();
2002
+
2003
+ root.AddSingularNode(singmp->root, false);
2004
+
2005
+ /*
2006
+ int maxlevel = 0;
2007
+ for (auto [i,num] : Enumerate(RegularMLMultiPole::nodes_on_level))
2008
+ if (num > 0) maxlevel = i;
2009
+
2010
+ for (int i = 0; i <= maxlevel; i++)
2011
+ cout << "reg " << i << ": " << RegularMLMultiPole::nodes_on_level[i] << endl;
2012
+ */
2013
+
2014
+ root.LocalizeExpansion(false);
2015
+ }
2016
+
2017
+ double Norm() const
2018
+ {
2019
+ return root.Norm();
2020
+ }
2021
+
2022
+ size_t NumCoefficients() const
2023
+ {
2024
+ return root.NumCoefficients();
2025
+ }
2026
+
2027
+ Complex Evaluate (Vec<3> p) const
2028
+ {
2029
+ // static Timer t("mptool Eval MLMP regular"); RegionTimer r(t);
2030
+ if (L2Norm(p-root.center) > root.r) return 0.0;
2031
+ return root.Evaluate(p);
2032
+ }
2033
+
2034
+
2035
+ };
2036
+
2037
+ Array<size_t> RegularMLMultiPole::nodes_on_level(100);
2038
+ Array<size_t> SingularMLMultiPole::nodes_on_level(100);
2039
+
2040
+ // ******************** Coefficient Functions *********************
2041
+
2042
+ class SphericalHarmonicsCF : public CoefficientFunction
2043
+ {
2044
+ SphericalHarmonics sh;
2045
+ public:
2046
+ SphericalHarmonicsCF (int order)
2047
+ : CoefficientFunction(1, true), sh(order) { }
2048
+ Complex & Coef(int n, int m) { return sh.Coef(n,m); }
2049
+
2050
+ virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
2051
+ { throw Exception("real eval not available"); }
2052
+
2053
+ virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
2054
+ {
2055
+ values(0) = sh.Eval(mip.GetPoint());
2056
+ }
2057
+
2058
+ virtual void Evaluate (const BaseMappedIntegrationRule & ir, BareSliceMatrix<Complex> values) const override
2059
+ {
2060
+ for (int i = 0; i < ir.Size(); i++)
2061
+ {
2062
+ auto & mip = ir[i];
2063
+ values(i,0) = sh.Eval(mip.GetPoint());
2064
+ }
2065
+ }
2066
+
2067
+ auto & SH() { return sh; }
2068
+ };
2069
+
2070
+
2071
+
2072
+ template <typename RADIAL>
2073
+ class MultiPoleCF : public CoefficientFunction
2074
+ {
2075
+ MultiPole<RADIAL> mp;
2076
+ Vec<3> center;
2077
+ public:
2078
+ MultiPoleCF (int order, double kappa, Vec<3> acenter, double scale = 1)
2079
+ : CoefficientFunction(1, true), mp(order, kappa, scale), center(acenter) { }
2080
+
2081
+ Complex & Coef(int n, int m) { return mp.Coef(n,m); }
2082
+ auto & SH() { return mp.SH(); }
2083
+ auto & MP() { return mp; }
2084
+ Vec<3> Center() const { return center; }
2085
+
2086
+ virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
2087
+ { throw Exception("real eval not available"); }
2088
+
2089
+ virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
2090
+ {
2091
+ values(0) = mp.Eval(mip.GetPoint()-center);
2092
+ }
2093
+
2094
+ template <typename TARGET>
2095
+ void ShiftZ (double z, MultiPole<TARGET> & target) { mp.ShiftZ(z, target); }
2096
+
2097
+ using CoefficientFunction::Transform;
2098
+ template <typename TARGET>
2099
+ void Transform (MultiPoleCF<TARGET> & target)
2100
+ {
2101
+ mp.Transform (target.MP(), target.Center()-center);
2102
+ }
2103
+ };
2104
+
2105
+
2106
+ class SingularMLMultiPoleCF : public CoefficientFunction
2107
+ {
2108
+ shared_ptr<SingularMLMultiPole> mlmp;
2109
+ public:
2110
+ SingularMLMultiPoleCF (Vec<3> center, double r, int order, double kappa)
2111
+ : CoefficientFunction(1, true), mlmp{make_shared<SingularMLMultiPole>(center, r, order, kappa)} { }
2112
+
2113
+ virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
2114
+ { throw Exception("real eval not available"); }
2115
+
2116
+ virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
2117
+ {
2118
+ values(0) = mlmp->Evaluate(mip.GetPoint());
2119
+ }
2120
+
2121
+ shared_ptr<SingularMLMultiPole> MLMP() { return mlmp; }
2122
+ };
2123
+
2124
+
2125
+ class RegularMLMultiPoleCF : public CoefficientFunction
2126
+ {
2127
+ RegularMLMultiPole mlmp;
2128
+ public:
2129
+ RegularMLMultiPoleCF (shared_ptr<SingularMLMultiPoleCF> asingmp, Vec<3> center, double r, int order)
2130
+ : CoefficientFunction(1, true), mlmp(asingmp->MLMP(), center, r, order) { }
2131
+
2132
+ virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
2133
+ { throw Exception("real eval not available"); }
2134
+
2135
+ virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
2136
+ {
2137
+ values(0) = mlmp.Evaluate(mip.GetPoint());
2138
+ }
2139
+
2140
+ RegularMLMultiPole & MLMP() { return mlmp; }
2141
+ };
2142
+
2143
+
2144
+ }
2145
+ #endif