ngsolve 6.2.2501.post47.dev1__cp313-cp313-macosx_10_15_universal2.whl → 6.2.2501.post48.dev1__cp313-cp313-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.
- netgen/include/arnoldi.hpp +55 -0
- netgen/include/bandmatrix.hpp +334 -0
- netgen/include/basematrix.hpp +957 -0
- netgen/include/basevector.hpp +1268 -0
- netgen/include/bdbequations.hpp +2752 -0
- netgen/include/bdbintegrator.hpp +1660 -0
- netgen/include/bessel.hpp +1064 -0
- netgen/include/bilinearform.hpp +963 -0
- netgen/include/bla.hpp +29 -0
- netgen/include/blockalloc.hpp +95 -0
- netgen/include/blockjacobi.hpp +316 -0
- netgen/include/bspline.hpp +114 -0
- netgen/include/calcinverse.hpp +141 -0
- netgen/include/cg.hpp +368 -0
- netgen/include/chebyshev.hpp +44 -0
- netgen/include/cholesky.hpp +720 -0
- netgen/include/clapack.h +7254 -0
- netgen/include/code_generation.hpp +296 -0
- netgen/include/coefficient.hpp +2033 -0
- netgen/include/coefficient_impl.hpp +19 -0
- netgen/include/coefficient_stdmath.hpp +167 -0
- netgen/include/commutingAMG.hpp +106 -0
- netgen/include/comp.hpp +79 -0
- netgen/include/compatibility.hpp +41 -0
- netgen/include/complex_wrapper.hpp +73 -0
- netgen/include/compressedfespace.hpp +110 -0
- netgen/include/contact.hpp +231 -0
- netgen/include/diagonalmatrix.hpp +154 -0
- netgen/include/differentialoperator.hpp +276 -0
- netgen/include/diffop.hpp +1286 -0
- netgen/include/diffop_impl.hpp +326 -0
- netgen/include/discontinuous.hpp +84 -0
- netgen/include/dump.hpp +949 -0
- netgen/include/eigen.hpp +60 -0
- netgen/include/eigensystem.hpp +18 -0
- netgen/include/elasticity_equations.hpp +595 -0
- netgen/include/elementbyelement.hpp +195 -0
- netgen/include/elementtopology.hpp +1760 -0
- netgen/include/elementtransformation.hpp +339 -0
- netgen/include/evalfunc.hpp +405 -0
- netgen/include/expr.hpp +1655 -0
- netgen/include/facetfe.hpp +175 -0
- netgen/include/facetfespace.hpp +178 -0
- netgen/include/facethofe.hpp +111 -0
- netgen/include/facetsurffespace.hpp +112 -0
- netgen/include/fe_interfaces.hpp +32 -0
- netgen/include/fem.hpp +87 -0
- netgen/include/fesconvert.hpp +14 -0
- netgen/include/fespace.hpp +1445 -0
- netgen/include/finiteelement.hpp +286 -0
- netgen/include/globalinterfacespace.hpp +77 -0
- netgen/include/globalspace.hpp +115 -0
- netgen/include/gridfunction.hpp +525 -0
- netgen/include/h1amg.hpp +41 -0
- netgen/include/h1hofe.hpp +188 -0
- netgen/include/h1hofe_impl.hpp +1262 -0
- netgen/include/h1hofefo.hpp +148 -0
- netgen/include/h1hofefo_impl.hpp +185 -0
- netgen/include/h1hofespace.hpp +167 -0
- netgen/include/h1lofe.hpp +1237 -0
- netgen/include/h1lumping.hpp +35 -0
- netgen/include/hcurl_equations.hpp +1352 -0
- netgen/include/hcurlcurlfe.hpp +2221 -0
- netgen/include/hcurlcurlfespace.hpp +78 -0
- netgen/include/hcurlfe.hpp +259 -0
- netgen/include/hcurlfe_utils.hpp +107 -0
- netgen/include/hcurlhdiv_dshape.hpp +857 -0
- netgen/include/hcurlhdivfes.hpp +308 -0
- netgen/include/hcurlhofe.hpp +175 -0
- netgen/include/hcurlhofe_impl.hpp +1871 -0
- netgen/include/hcurlhofespace.hpp +193 -0
- netgen/include/hcurllofe.hpp +1146 -0
- netgen/include/hdiv_equations.hpp +865 -0
- netgen/include/hdivdivfe.hpp +2923 -0
- netgen/include/hdivdivsurfacespace.hpp +76 -0
- netgen/include/hdivfe.hpp +206 -0
- netgen/include/hdivfe_utils.hpp +716 -0
- netgen/include/hdivfes.hpp +75 -0
- netgen/include/hdivhofe.hpp +447 -0
- netgen/include/hdivhofe_impl.hpp +1107 -0
- netgen/include/hdivhofefo.hpp +229 -0
- netgen/include/hdivhofespace.hpp +175 -0
- netgen/include/hdivhosurfacefespace.hpp +106 -0
- netgen/include/hdivlofe.hpp +773 -0
- netgen/include/hidden.hpp +74 -0
- netgen/include/householder.hpp +181 -0
- netgen/include/hypre_ams_precond.hpp +123 -0
- netgen/include/hypre_precond.hpp +73 -0
- netgen/include/integrator.hpp +2024 -0
- netgen/include/integratorcf.hpp +253 -0
- netgen/include/interpolate.hpp +49 -0
- netgen/include/intrule.hpp +2541 -0
- netgen/include/irspace.hpp +49 -0
- netgen/include/jacobi.hpp +136 -0
- netgen/include/l2hofe.hpp +193 -0
- netgen/include/l2hofe_impl.hpp +564 -0
- netgen/include/l2hofefo.hpp +542 -0
- netgen/include/l2hofespace.hpp +344 -0
- netgen/include/la.hpp +38 -0
- netgen/include/linearform.hpp +266 -0
- netgen/include/matrix.hpp +2140 -0
- netgen/include/memusage.hpp +41 -0
- netgen/include/meshaccess.hpp +1358 -0
- netgen/include/mgpre.hpp +204 -0
- netgen/include/mptools.hpp +2145 -0
- netgen/include/multigrid.hpp +42 -0
- netgen/include/multivector.hpp +447 -0
- netgen/include/mumpsinverse.hpp +187 -0
- netgen/include/mycomplex.hpp +361 -0
- netgen/include/ng_lapack.hpp +1661 -0
- netgen/include/ngblas.hpp +1099 -0
- netgen/include/ngs_defines.hpp +30 -0
- netgen/include/ngs_stdcpp_include.hpp +106 -0
- netgen/include/ngs_utils.hpp +121 -0
- netgen/include/ngsobject.hpp +1019 -0
- netgen/include/ngsstream.hpp +113 -0
- netgen/include/ngstd.hpp +72 -0
- netgen/include/nodalhofe.hpp +96 -0
- netgen/include/nodalhofe_impl.hpp +141 -0
- netgen/include/normalfacetfe.hpp +223 -0
- netgen/include/normalfacetfespace.hpp +98 -0
- netgen/include/normalfacetsurfacefespace.hpp +84 -0
- netgen/include/order.hpp +251 -0
- netgen/include/parallel_matrices.hpp +222 -0
- netgen/include/paralleldofs.hpp +340 -0
- netgen/include/parallelngs.hpp +23 -0
- netgen/include/parallelvector.hpp +269 -0
- netgen/include/pardisoinverse.hpp +200 -0
- netgen/include/periodic.hpp +125 -0
- netgen/include/plateaufespace.hpp +25 -0
- netgen/include/pml.hpp +275 -0
- netgen/include/pmltrafo.hpp +631 -0
- netgen/include/postproc.hpp +142 -0
- netgen/include/precomp.hpp +60 -0
- netgen/include/preconditioner.hpp +602 -0
- netgen/include/prolongation.hpp +235 -0
- netgen/include/python_comp.hpp +107 -0
- netgen/include/python_fem.hpp +89 -0
- netgen/include/python_linalg.hpp +58 -0
- netgen/include/python_ngstd.hpp +385 -0
- netgen/include/recursive_pol.hpp +4844 -0
- netgen/include/recursive_pol_tet.hpp +395 -0
- netgen/include/recursive_pol_trig.hpp +492 -0
- netgen/include/reorderedfespace.hpp +81 -0
- netgen/include/sample_sort.hpp +105 -0
- netgen/include/scalarfe.hpp +335 -0
- netgen/include/shapefunction_utils.hpp +113 -0
- netgen/include/simd_complex.hpp +284 -0
- netgen/include/smoother.hpp +253 -0
- netgen/include/solve.hpp +89 -0
- netgen/include/sparsecholesky.hpp +313 -0
- netgen/include/sparsematrix.hpp +1038 -0
- netgen/include/sparsematrix_dyn.hpp +91 -0
- netgen/include/sparsematrix_impl.hpp +920 -0
- netgen/include/special_matrix.hpp +461 -0
- netgen/include/specialelement.hpp +125 -0
- netgen/include/statushandler.hpp +33 -0
- netgen/include/stringops.hpp +12 -0
- netgen/include/superluinverse.hpp +136 -0
- netgen/include/symbolicintegrator.hpp +849 -0
- netgen/include/symmetricmatrix.hpp +144 -0
- netgen/include/tangentialfacetfe.hpp +224 -0
- netgen/include/tangentialfacetfespace.hpp +106 -0
- netgen/include/tensor.hpp +522 -0
- netgen/include/tensorcoefficient.hpp +446 -0
- netgen/include/tensorproductintegrator.hpp +113 -0
- netgen/include/thcurlfe.hpp +128 -0
- netgen/include/thcurlfe_impl.hpp +380 -0
- netgen/include/thdivfe.hpp +80 -0
- netgen/include/thdivfe_impl.hpp +426 -0
- netgen/include/tpdiffop.hpp +461 -0
- netgen/include/tpfes.hpp +133 -0
- netgen/include/tpintrule.hpp +224 -0
- netgen/include/triangular.hpp +465 -0
- netgen/include/tscalarfe.hpp +245 -0
- netgen/include/tscalarfe_impl.hpp +1029 -0
- netgen/include/umfpackinverse.hpp +148 -0
- netgen/include/vector.hpp +1219 -0
- netgen/include/voxelcoefficientfunction.hpp +41 -0
- netgen/include/vtkoutput.hpp +198 -0
- netgen/include/vvector.hpp +208 -0
- netgen/include/webgui.hpp +92 -0
- netgen/libngbla.dylib +0 -0
- netgen/libngcomp.dylib +0 -0
- netgen/libngfem.dylib +0 -0
- netgen/libngla.dylib +0 -0
- netgen/libngsolve.dylib +0 -0
- netgen/libngstd.dylib +0 -0
- ngsolve/__init__.pyi +231 -0
- ngsolve/bla.pyi +1139 -0
- ngsolve/bvp.pyi +32 -0
- ngsolve/cmake/NGSolveConfig.cmake +102 -0
- ngsolve/cmake/ngsolve-targets-release.cmake +69 -0
- ngsolve/cmake/ngsolve-targets.cmake +163 -0
- ngsolve/comp/__init__.pyi +5382 -0
- ngsolve/comp/pml.pyi +89 -0
- ngsolve/config/__init__.py +1 -0
- ngsolve/config/__init__.pyi +43 -0
- ngsolve/config/__main__.py +4 -0
- ngsolve/config/config.py +60 -0
- ngsolve/config/config.pyi +45 -0
- ngsolve/demos/TensorProduct/__init__.py +0 -0
- ngsolve/demos/TensorProduct/tp_dg_1d_1d.py +80 -0
- ngsolve/demos/TensorProduct/tp_dg_1d_2d.py +73 -0
- ngsolve/demos/TensorProduct/tp_dg_2d_1d.py +72 -0
- ngsolve/demos/TensorProduct/tp_dg_2d_2d.py +66 -0
- ngsolve/demos/__init__.py +0 -0
- ngsolve/demos/howto/__init__.py +0 -0
- ngsolve/demos/howto/hhj.py +44 -0
- ngsolve/demos/howto/hybrid_dg.py +53 -0
- ngsolve/demos/howto/mixed.py +30 -0
- ngsolve/demos/howto/nonlin.py +29 -0
- ngsolve/demos/howto/pickling.py +26 -0
- ngsolve/demos/howto/pml.py +31 -0
- ngsolve/demos/howto/taskmanager.py +20 -0
- ngsolve/demos/howto/tdnns.py +47 -0
- ngsolve/demos/howto/timeDG-skeleton.py +45 -0
- ngsolve/demos/howto/timeDG.py +38 -0
- ngsolve/demos/howto/timeDGlap.py +42 -0
- ngsolve/demos/howto/timeDGwave.py +61 -0
- ngsolve/demos/intro/__init__.py +0 -0
- ngsolve/demos/intro/adaptive.py +123 -0
- ngsolve/demos/intro/cmagnet.py +62 -0
- ngsolve/demos/intro/elasticity.py +76 -0
- ngsolve/demos/intro/navierstokes.py +74 -0
- ngsolve/demos/intro/poisson.ipynb +170 -0
- ngsolve/demos/intro/poisson.py +41 -0
- ngsolve/demos/mpi/__init__.py +0 -0
- ngsolve/demos/mpi/mpi_cmagnet.py +87 -0
- ngsolve/demos/mpi/mpi_navierstokes.py +117 -0
- ngsolve/demos/mpi/mpi_poisson.py +89 -0
- ngsolve/demos/mpi/mpi_timeDG.py +82 -0
- ngsolve/directsolvers.pyi +18 -0
- ngsolve/eigenvalues.pyi +30 -0
- ngsolve/fem.pyi +1707 -0
- ngsolve/krylovspace.pyi +309 -0
- ngsolve/la.pyi +1218 -0
- ngsolve/ngslib.so +0 -0
- ngsolve/ngstd.pyi +58 -0
- ngsolve/nonlinearsolvers.pyi +98 -0
- ngsolve/preconditioners.pyi +6 -0
- ngsolve/solve.pyi +108 -0
- ngsolve/solvers.pyi +14 -0
- ngsolve/timestepping.pyi +34 -0
- ngsolve/timing.pyi +57 -0
- ngsolve/utils.pyi +279 -0
- ngsolve-6.2.2501.post48.dev1.data/data/Netgen.icns +0 -0
- ngsolve-6.2.2501.post48.dev1.data/data/bin/ngscxx +17 -0
- ngsolve-6.2.2501.post48.dev1.data/data/bin/ngsld +13 -0
- ngsolve-6.2.2501.post48.dev1.data/data/bin/ngsolve.tcl +648 -0
- ngsolve-6.2.2501.post48.dev1.data/data/bin/ngspy +2 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/beam.geo +17 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/beam.vol +240 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/chip.in2d +41 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/chip.vol +614 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coil.geo +12 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coil.vol +2560 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coilshield.geo +24 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/coilshield.vol +3179 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/cube.geo +19 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/cube.vol +1832 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d10_DGdoubleglazing.pde +50 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d11_chip_nitsche.pde +40 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d1_square.pde +43 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d2_chip.pde +35 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d3_helmholtz.pde +22 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d4_cube.pde +46 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d5_beam.pde +74 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d6_shaft.pde +73 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d7_coil.pde +50 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d8_coilshield.pde +49 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/d9_hybridDG.pde +72 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/doubleglazing.in2d +27 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/doubleglazing.vol +737 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/piezo2d40round4.vol.gz +0 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/shaft.geo +73 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/shaft.vol +4291 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/square.in2d +17 -0
- ngsolve-6.2.2501.post48.dev1.data/data/share/ngsolve/square.vol +149 -0
- {ngsolve-6.2.2501.post47.dev1.dist-info → ngsolve-6.2.2501.post48.dev1.dist-info}/METADATA +1 -1
- ngsolve-6.2.2501.post48.dev1.dist-info/RECORD +304 -0
- ngsolve-6.2.2501.post47.dev1.dist-info/RECORD +0 -25
- {ngsolve-6.2.2501.post47.dev1.dist-info → ngsolve-6.2.2501.post48.dev1.dist-info}/LICENSE +0 -0
- {ngsolve-6.2.2501.post47.dev1.dist-info → ngsolve-6.2.2501.post48.dev1.dist-info}/WHEEL +0 -0
- {ngsolve-6.2.2501.post47.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
|