ngsolve 6.2.2501.post55.dev1__cp313-cp313-macosx_10_15_universal2.whl → 6.2.2501.post70.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.

Files changed (59) hide show
  1. netgen/include/ectypes.hpp +121 -0
  2. netgen/include/h1lofe.hpp +3 -0
  3. netgen/include/mptools.hpp +86 -1176
  4. netgen/include/vector.hpp +8 -0
  5. netgen/libngbla.dylib +0 -0
  6. netgen/libngcomp.dylib +0 -0
  7. netgen/libngfem.dylib +0 -0
  8. netgen/libngla.dylib +0 -0
  9. netgen/libngstd.dylib +0 -0
  10. ngsolve/__init__.pyi +3 -3
  11. ngsolve/cmake/NGSolveConfig.cmake +1 -1
  12. ngsolve/config/__init__.pyi +6 -6
  13. ngsolve/config/config.py +5 -5
  14. ngsolve/config/config.pyi +6 -6
  15. ngsolve/directsolvers.pyi +1 -1
  16. ngsolve/fem.pyi +20 -3
  17. ngsolve/krylovspace.pyi +2 -2
  18. ngsolve/nonlinearsolvers.pyi +1 -1
  19. ngsolve/timestepping.pyi +3 -3
  20. ngsolve/timing.pyi +1 -1
  21. ngsolve/utils.pyi +3 -2
  22. {ngsolve-6.2.2501.post55.dev1.dist-info → ngsolve-6.2.2501.post70.dev1.dist-info}/METADATA +1 -1
  23. {ngsolve-6.2.2501.post55.dev1.dist-info → ngsolve-6.2.2501.post70.dev1.dist-info}/RECORD +59 -58
  24. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/Netgen.icns +0 -0
  25. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/bin/ngscxx +0 -0
  26. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/bin/ngsld +0 -0
  27. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/bin/ngsolve.tcl +0 -0
  28. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/bin/ngspy +0 -0
  29. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/beam.geo +0 -0
  30. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/beam.vol +0 -0
  31. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/chip.in2d +0 -0
  32. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/chip.vol +0 -0
  33. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/coil.geo +0 -0
  34. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/coil.vol +0 -0
  35. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/coilshield.geo +0 -0
  36. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/coilshield.vol +0 -0
  37. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/cube.geo +0 -0
  38. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/cube.vol +0 -0
  39. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d10_DGdoubleglazing.pde +0 -0
  40. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d11_chip_nitsche.pde +0 -0
  41. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d1_square.pde +0 -0
  42. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d2_chip.pde +0 -0
  43. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d3_helmholtz.pde +0 -0
  44. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d4_cube.pde +0 -0
  45. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d5_beam.pde +0 -0
  46. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d6_shaft.pde +0 -0
  47. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d7_coil.pde +0 -0
  48. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d8_coilshield.pde +0 -0
  49. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/d9_hybridDG.pde +0 -0
  50. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/doubleglazing.in2d +0 -0
  51. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/doubleglazing.vol +0 -0
  52. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/piezo2d40round4.vol.gz +0 -0
  53. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/shaft.geo +0 -0
  54. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/shaft.vol +0 -0
  55. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/square.in2d +0 -0
  56. {ngsolve-6.2.2501.post55.dev1.data → ngsolve-6.2.2501.post70.dev1.data}/data/share/ngsolve/square.vol +0 -0
  57. {ngsolve-6.2.2501.post55.dev1.dist-info → ngsolve-6.2.2501.post70.dev1.dist-info}/LICENSE +0 -0
  58. {ngsolve-6.2.2501.post55.dev1.dist-info → ngsolve-6.2.2501.post70.dev1.dist-info}/WHEEL +0 -0
  59. {ngsolve-6.2.2501.post55.dev1.dist-info → ngsolve-6.2.2501.post70.dev1.dist-info}/top_level.txt +0 -0
@@ -8,14 +8,14 @@
8
8
 
9
9
  #include <bla.hpp>
10
10
  #include <coefficient.hpp>
11
-
11
+ #include <recursive_pol.hpp>
12
12
 
13
13
  namespace ngfem
14
14
  {
15
15
 
16
16
 
17
17
 
18
- class SphericalHarmonics
18
+ class NGS_DLL_HEADER SphericalHarmonics
19
19
  {
20
20
  int order;
21
21
  Vector<Complex> coefs;
@@ -34,10 +34,10 @@ namespace ngfem
34
34
 
35
35
  auto CoefsN (int n) const
36
36
  {
37
- return FlatVector<Complex> (2*n+1, &coefs(n*(n+1)-n));
37
+ return coefs.RangeN(n*n, 2*n+1);
38
38
  }
39
39
 
40
- auto Polar (Vec<3> x) const
40
+ static std::tuple<double,double> Polar (Vec<3> x)
41
41
  {
42
42
  double phi, theta;
43
43
  if (x(0) == 0 && x(1) == 0)
@@ -50,7 +50,7 @@ namespace ngfem
50
50
  phi = atan2(x(1), x(0));
51
51
  theta = acos(x(2)/L2Norm(x));
52
52
  }
53
- return tuple{theta, phi};
53
+ return { theta, phi };
54
54
  }
55
55
 
56
56
  Complex Eval (Vec<3> x) const
@@ -59,36 +59,7 @@ namespace ngfem
59
59
  return Eval(theta, phi);
60
60
  }
61
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
-
62
+ Complex Eval (double theta, double phi) const;
92
63
 
93
64
  Complex EvalOrder (int n, Vec<3> x) const
94
65
  {
@@ -96,39 +67,7 @@ namespace ngfem
96
67
  return EvalOrder(n, theta, phi);
97
68
  }
98
69
 
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
-
70
+ Complex EvalOrder (int n, double theta, double phi) const;
132
71
 
133
72
  void EvalOrders (Vec<3> x, FlatVector<Complex> vals) const
134
73
  {
@@ -136,99 +75,15 @@ namespace ngfem
136
75
  return EvalOrders(theta, phi, vals);
137
76
  }
138
77
 
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
-
78
+ void EvalOrders (double theta, double phi, FlatVector<Complex> vals) const;
204
79
 
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
-
80
+ void Calc (Vec<3> x, FlatVector<Complex> shapes);
230
81
 
82
+
83
+ void RotateZ (double alpha);
84
+ void RotateY (double alpha);
231
85
 
86
+
232
87
  static double CalcAmn (int m, int n)
233
88
  {
234
89
  if (m < 0) m=-m;
@@ -251,422 +106,44 @@ namespace ngfem
251
106
 
252
107
  // Nail A. Gumerov and Ramani Duraiswami book, formula (2.2.12)
253
108
  // add directional derivative divided by kappa to res, both multipoles need same scaling
254
- void DirectionalDiffAdd (Vec<3> d, SphericalHarmonics & res, double scale = 1)
255
- {
256
- double fx = d(0);
257
- double fy = d(1);
258
- double fz = d(2);
259
- double invscale = 1./scale;
260
-
261
- for (int n = 0; n < order; n++)
262
- for (int m = -n; m <= n; m++)
263
- {
264
- double amn = CalcAmn(m,n);
265
- double bmn1 = CalcBmn(-m-1, n+1);
266
- double bmn2 = CalcBmn(m-1,n+1);
267
-
268
- res.Coef(n+1, m-1) += invscale * Complex(0.5*fx,0.5*fy)*bmn2 * Coef(n,m);
269
- res.Coef(n+1, m ) -= invscale * fz*amn * Coef(n,m);
270
- res.Coef(n+1, m+1) += invscale * Complex(0.5*fx,-0.5*fy)*bmn1 * Coef(n,m);
271
-
272
- res.Coef(n, m) += scale * Complex(-0.5*fx,0.5*fy)*bmn2 * Coef(n+1,m-1);
273
- res.Coef(n, m) += scale * fz*amn * Coef(n+1,m);
274
- res.Coef(n, m) += scale * Complex(-0.5*fx,-0.5*fy)*bmn1 * Coef(n+1,m+1);
275
- }
276
- }
277
-
278
- void RotateY (double alpha)
279
- {
280
- LocalHeap lh(8*6*sqr(order) + 8*15*order + 500);
281
-
282
- static Timer t("mptool sh RotateY"); RegionTimer rg(t);
283
- /*
284
- static std::map<int, unique_ptr<Timer<>>> timers;
285
- static std::map<int, unique_ptr<Timer<>>> timerstrafo;
286
- if (timers.find(order)==timers.end())
287
- {
288
- timers[order] = make_unique<Timer<>> (string("mptools sh RotateY ")+ToString(order));
289
- timerstrafo[order] = make_unique<Timer<>> (string("mptools sh RotateY trafo ")+ToString(order));
290
- }
291
- RegionTimer rg(*timers[order]);
292
- */
293
- double s = sin(alpha);
294
- double c = cos(alpha);
295
-
296
- FlatMatrix<> normalized_leg_func(order+2, order+2, lh);
297
- NormalizedLegendreFunctions(order+1, order+1, c, normalized_leg_func);
298
-
299
- if (alpha < 0)
300
- for (int i = 1; i <= order+1; i+=2)
301
- normalized_leg_func.Row(i) *= -1;
302
-
303
- // cout << "leg = " << endl << normalized_leg_func << endl;
304
- FlatVector<> Dmn(2*order+1, lh);
109
+ void DirectionalDiffAdd (Vec<3> d, SphericalHarmonics & res, double scale = 1);
305
110
 
306
- for (int n=1; n <= order; n++)
307
- {
308
- HeapReset hr(lh);
309
-
310
- FlatMatrix<double> trafo(n+1, 2*n+1, lh);
311
- /*
312
- Recursive Computation of Spherical Harmonic Rotation Coefficients of Large Degree
313
- Nail A. Gumerov and Ramani Duraiswami
314
- within Excursions in Harmonic Analysis, Volume 3
315
-
316
- page 130
317
- */
318
-
319
- // Step 2
320
- // H(0,m)
321
- trafo.Col(n) = 1.0/sqrt(2*n+1) * normalized_leg_func.Col(n).Range(n+1);
322
- for (int m = 1; m <= n; m += 2) trafo(m,n) *= -1;
323
- // Step 3
324
- // H(1,m)
325
- FlatVector<double> tmp = 1.0/sqrt(2*n+3) * normalized_leg_func.Col(n+1).Range(n+2) | lh;
326
- for (int m = 1; m < tmp.Size(); m += 2) tmp(m) *= -1;
327
- for (int m = 1; m <= n; m++)
328
- trafo.Col(n+1)(m) = 1/CalcBmn(0,n+1) * ( CalcBmn(-m-1, n+1)*(1-c)/2 * tmp(m+1)
329
- - CalcBmn(m-1,n+1)*(1+c)/2 * tmp(m-1)
330
- - CalcAmn(m,n) * s*tmp(m));
331
-
332
- // Step 4
333
- // diamond - recursion
334
- for (int mp = -n; mp <= n; mp++)
335
- Dmn(order+mp) = CalcDmn(mp, n);
336
-
337
- for (int mp = 1; mp < n; mp++)
338
- {
339
- double invDmn = 1.0 / Dmn(order+mp);
340
- for (int m = mp; m < n; m++)
341
- trafo(m, n+mp+1) = invDmn * ( Dmn(order+mp-1) *trafo(m ,n+mp-1)
342
- -Dmn(order+m-1)*trafo(m-1,n+mp)
343
- +Dmn(order+m) *trafo(m+1,n+mp));
344
- int m = n;
345
- trafo(m, n+mp+1) = invDmn * ( Dmn(order+mp-1,n)*trafo(m ,n+mp-1)
346
- -Dmn(order+m-1,n)*trafo(m-1,n+mp));
347
- }
348
-
349
- // Step 5
350
- // diamond - recursion, negative
351
- for (int mp = 0; mp > -n; mp--)
352
- {
353
- double invDmn = 1.0 / Dmn(order+mp-1);
354
- for (int m = -mp+1; m < n; m++)
355
- trafo(m, n+mp-1) = invDmn * ( Dmn(order+mp,n)*trafo(m ,n+mp+1)
356
- +Dmn(order+m-1,n)*trafo(m-1,n+mp)
357
- -Dmn(order+m ,n)*trafo(m+1,n+mp));
358
- int m = n;
359
- trafo(m, n+mp-1) = invDmn * ( Dmn(order+mp,n)*trafo(m ,n+mp+1)
360
- +Dmn(order+m-1,n)*trafo(m-1,n+mp));
361
- }
362
-
363
- // RegionTimer rgtrafo(*timerstrafo[order]);
364
- // Step 6
365
- // symmetries in m and mp
366
- for (int m = 0; m <= n; m++)
367
- {
368
- auto dst = trafo.Row(m).Range(n+m, n+n+1);
369
- auto src = trafo.Col(n+m).Range(m, n+1);
370
- dst = src;
371
- }
372
- for (int m = 0; m <= n; m++)
373
- {
374
- auto dst = trafo.Row(m).Range(n-n, n-m+1).Reversed();
375
- auto src = trafo.Col(n-m).Range(m, n+1);
376
- dst = src;
377
- }
378
- /*
379
- double errortho = L2Norm( Matrix(trafo*Trans(trafo) - Identity(n+1)));
380
- if (errortho > 1e-10)
381
- {
382
- *testout << "n = " << n << " order = " << Order() << ", alpha = " << alpha << ", errortho = " << errortho << endl;
383
- if (n < 10)
384
- *testout << trafo*Trans(trafo) << endl;
385
- }
386
- */
387
-
388
- FlatVector<Complex> cn = CoefsN(n);
389
- FlatVector<Complex> old = cn | lh;
390
-
391
- cn.Slice(0,1) = Trans(trafo) * old.Range(n, 2*n+1);
392
- cn.Slice(0,1).Reversed() += Trans(trafo.Rows(1,n+1)) * old.Range(0,n).Reversed();
393
-
394
- for (int m = 1; m <= n; m+=2)
395
- {
396
- cn(n+m) *= -1;
397
- cn(n-m) *= -1;
398
- }
399
- }
400
- }
401
-
402
111
  };
403
112
 
404
113
 
405
114
  // https://fortran-lang.discourse.group/t/looking-for-spherical-bessel-and-hankel-functions-of-first-and-second-kind-and-arbitrary-order/2308/2
115
+ NGS_DLL_HEADER
116
+ void besseljs3d (int nterms, double z, double scale,
117
+ FlatVector<double> fjs, FlatVector<double> fjder);
406
118
 
407
- // adapted from fmm3d
408
- template <typename Tz>
409
- void besseljs3d (int nterms, Tz z, double scale,
410
- FlatVector<Tz> fjs, FlatVector<Tz> fjder)
411
- {
412
- /*
413
- c**********************************************************************
414
- c
415
- c PURPOSE:
416
- c
417
- c This subroutine evaluates the first NTERMS spherical Bessel
418
- c functions and if required, their derivatives.
419
- c It incorporates a scaling parameter SCALE so that
420
- c
421
- c fjs_n(z)=j_n(z)/SCALE^n
422
- c fjder_n(z)=\frac{\partial fjs_n(z)}{\partial z}
423
- c
424
- c INPUT:
425
- c
426
- c nterms (integer): order of expansion of output array fjs
427
- c z (complex *16): argument of the spherical Bessel functions
428
- c scale (real *8) : scaling factor (discussed above)
429
- c ifder (integer): flag indicating whether to calculate "fjder"
430
- c 0 NO
431
- c 1 YES
432
- c OUTPUT:
433
- c fjs (complex *16): array of scaled Bessel functions.
434
- c fjder (complex *16): array of derivs of scaled Bessel functions.
435
- c
436
- c
437
- */
119
+ NGS_DLL_HEADER
120
+ void besseljs3d (int nterms, Complex z, double scale,
121
+ FlatVector<Complex> fjs, FlatVector<Complex> fjder);
438
122
 
439
123
 
440
- // c ... Initializing ...
441
-
442
- // set to asymptotic values if argument is sufficiently small
443
- if (abs(z) < 1e-200)
444
- {
445
- fjs(0) = 1;
446
- for (int i = 1; i <= nterms; i++)
447
- fjs(i) = 0.0;
448
-
449
- if (fjder.Size())
450
- {
451
- fjder = 0.0;
452
- fjder(1) = 1.0/(3*scale);
453
- }
454
- return;
455
- }
456
-
457
-
458
- // ... Step 1: recursion up to find ntop, starting from nterms
459
-
460
- Tz zinv=1.0/z;
461
-
462
- Tz fjm1 = 0.0;
463
- Tz fj0 = 1.0;
464
-
465
- /*
466
- c
467
- cc note max point for upward recurrence is
468
- c hard coded to nterms + 1000,
469
- c this might cause loss of accuracy for some
470
- c arguments in the complex plane for large
471
- c nterms. For example, it is a terrible idea
472
- c to use this code for z>>nterms^2
473
- */
474
-
475
- // int lwfjs = nterms + 100000;
476
- int ntop = nterms+1000;
477
-
478
- for (int i = nterms; ; i++)
479
- {
480
- double dcoef = 2*i+1.0;
481
- Tz fj1 = dcoef*zinv*fj0-fjm1;
482
- double dd = sqr(abs(fj1));
483
- if (dd > 1e40)
484
- {
485
- ntop=i+1;
486
- break;
487
- }
488
- fjm1 = fj0;
489
- fj0 = fj1;
490
- if (i > nterms+100000)
491
- throw Exception("bessel failed 1");
492
- }
493
-
494
- Array<bool> iscale(ntop+1);
495
- Vector<Tz> fjtmp(ntop+1);
496
-
497
- /*
498
- c ... Step 2: Recursion back down to generate the unscaled jfuns:
499
- c if magnitude exceeds UPBOUND2, rescale and continue the
500
- c recursion (saving the order at which rescaling occurred
501
- c in array iscale.
502
- */
503
-
504
- iscale = false;
505
-
506
- fjtmp(ntop) = 0.0;
507
- fjtmp(ntop-1) = 1.0;
508
- for (int i = ntop-1; i>=1; i--)
509
- {
510
- double dcoef = 2*i+1.0;
511
- fjtmp(i-1) = dcoef*zinv*fjtmp(i)-fjtmp(i+1);
512
- double dd = sqr(abs(fjtmp(i-1)));
513
- if (dd > 1e40)
514
- {
515
- fjtmp(i) *= 1e-40;
516
- fjtmp(i-1) *= 1e-40;
517
- iscale[i] = true;
518
- }
519
- }
520
-
521
- /*
522
- c
523
- c ... Step 3: go back up to the top and make sure that all
524
- c Bessel functions are scaled by the same factor
525
- c (i.e. the net total of times rescaling was invoked
526
- c on the way down in the previous loop).
527
- c At the same time, add scaling to fjs array.
528
- c
529
- */
530
-
531
- double scalinv = 1.0/scale;
532
- double sctot = 1.0;
533
- for (int i = 1; i <= ntop; i++)
534
- {
535
- sctot *= scalinv;
536
- if (iscale[i-1])
537
- sctot *= 1e-40;
538
- fjtmp(i) *= sctot;
539
- }
540
-
541
- // Determine the normalization parameter:
542
-
543
- fj0=sin(z)*zinv;
544
- Tz fj1=fj0*zinv-cos(z)*zinv;
545
-
546
- double d0=abs(fj0);
547
- double d1=abs(fj1);
548
- Tz zscale;
549
- if (d1 > d0)
550
- zscale=fj1/(fjtmp(1)*scale);
551
- else
552
- zscale=fj0/fjtmp(0);
553
-
554
- // Scale the jfuns by zscale:
555
-
556
- Tz ztmp=zscale;
557
- for (int i = 0; i <= nterms; i++)
558
- fjs(i)=fjtmp(i)*ztmp;
559
-
560
-
561
- // Finally, calculate the derivatives if desired:
562
-
563
- if (fjder.Size())
564
- {
565
- fjder(0) = -fjs(1)*scale;
566
- for (int i = 1; i <= nterms; i++)
567
- {
568
- double dc1=i/(2*i+1.0);
569
- double dc2=1.0-dc1;
570
- dc1=dc1*scalinv;
571
- dc2=dc2*scale;
572
- fjder(i)=(dc1*fjtmp(i-1)-dc2*fjtmp(i+1))*ztmp;
573
- }
574
- }
575
- }
576
-
577
-
578
-
579
-
580
124
  /*
581
- // from A. Barnett
582
- // http://www.fresco.org.uk/functions/barnett/index.htm
583
-
584
125
  spherical bessel functions of first (the j_n) and second (the y_n) kind.
585
-
126
+
586
127
  j0(r) = sin(r)/r
587
128
  j1(r) = (sin(r)-r cos(r)) / r**2
588
129
 
589
130
  y0(r) = -cos(r)/r
590
131
  y1(r) = (-cos(r)-r*sin(r)) / r**2
591
132
  */
133
+ NGS_DLL_HEADER
592
134
  void SBESJY (double x, int lmax,
593
135
  FlatVector<double> j,
594
136
  FlatVector<double> y,
595
137
  FlatVector<double> jp,
596
- FlatVector<double> yp)
597
- {
598
- if (x < 1e-8)
599
- {
600
- cout << "TODO: special treatment for small x" << endl;
601
- return;
602
- }
603
-
604
- double xinv = 1/x;
605
-
606
- if (lmax > 0)
607
- {
608
- double twoxi = 2*xinv;
609
- double sl = lmax*xinv;
610
- double tk = 2*sl+3*xinv;
611
- double cf1 = sl;
612
- double den = 1;
613
- if (abs(cf1) < 1e-8) cf1 = 1e-8;
614
- double c = cf1;
615
- double d = 0;
616
- for (int l = 1; l < 10000; l++)
617
- {
618
- c = tk-1/c;
619
- d = tk-d;
620
- if (abs(c) < 1e-8) c = 1e-8;
621
- if (abs(d) < 1e-8) d = 1e-8;
622
- d = 1/d;
623
- double dcf1 = d*c;
624
- cf1 *= dcf1;
625
- if (d < 0) den = -den;
626
- if (abs(dcf1-1) < 1e-10)
627
- break;
628
- tk += twoxi;
629
- // nfp = l;
630
- }
631
-
632
- j(lmax) = den;
633
- jp(lmax) = cf1*den;
634
- for (int l = lmax; l >= 1; l--)
635
- {
636
- j(l-1) = (sl+xinv)*j(l) + jp(l);
637
- sl = sl-xinv;
638
- jp(l-1) = sl*j(l-1) - j(l);
639
- }
640
- }
641
-
642
- double j0 = j(0);
643
- double jp0 = jp(0);
644
-
645
- // C------ CALCULATE THE L=0 SPHERICAL BESSEL FUNCTIONS DIRECTLY
646
- j(0) = xinv * sin(x);
647
- y(0) = -xinv * cos(x);
648
- jp(0) = -y(0)-xinv*j(0);
649
- yp(0) = j(0)-xinv*y(0);
650
-
651
- double omega = (abs(j0)>abs(jp0)) ? j(0)/j0 : jp(0) / jp0; // fix for x \approx 2 pi
652
- double sl = 0;
653
- for (int l = 1; l <=lmax; l++)
654
- {
655
- j(l) *= omega;
656
- jp(l) *= omega;
657
- y(l) = sl*y(l-1) - yp(l-1);
658
- sl += xinv;
659
- yp(l) = y(l-1) - (sl+xinv)*y(l);
660
- }
661
- }
662
-
138
+ FlatVector<double> yp);
663
139
 
664
140
 
141
+
665
142
  template <typename T>
666
143
  void SphericalBessel (int n, double rho, double scale, T && values)
667
144
  {
668
145
  Vector<double> j(n+1), jp(n+1);
669
- besseljs3d<double> (n, rho, scale, j, jp);
146
+ besseljs3d (n, rho, scale, j, jp);
670
147
  values = j;
671
148
  }
672
149
 
@@ -693,6 +170,7 @@ c
693
170
  Vector j(n+1), y(n+1), jp(n+1), yp(n+1);
694
171
  SBESJY (rho, n, j, y, jp, yp);
695
172
 
173
+ /*
696
174
  values = j + Complex(0,1) * y;
697
175
  if (scale != 1.0)
698
176
  {
@@ -703,6 +181,28 @@ c
703
181
  prod *= scale;
704
182
  }
705
183
  }
184
+ */
185
+
186
+
187
+ // the bessel-evaluation with scale
188
+ besseljs3d (n, rho, 1/scale, j, jp);
189
+
190
+ // Bessel y directly with the recurrence formula for (y, yp):
191
+ double x = rho;
192
+ double xinv = 1/x;
193
+ y(0) = -xinv * cos(x);
194
+ yp(0) = j(0)-xinv*y(0);
195
+
196
+ double sl = 0;
197
+ for (int l = 1; l <= n; l++)
198
+ {
199
+ y(l) = scale * (sl*y(l-1) - yp(l-1));
200
+ sl += xinv;
201
+ yp(l) = scale * y(l-1) - (sl+xinv)*y(l);
202
+ }
203
+
204
+ for (int i = 0; i <= n; i++)
205
+ values(i) = Complex (j(i), y(i));
706
206
  }
707
207
 
708
208
 
@@ -735,7 +235,7 @@ c
735
235
 
736
236
 
737
237
  template <typename RADIAL>
738
- class MultiPole
238
+ class NGS_DLL_HEADER MultiPole
739
239
  {
740
240
  SphericalHarmonics sh;
741
241
  double kappa;
@@ -766,86 +266,12 @@ c
766
266
  return *this;
767
267
  }
768
268
 
769
- Complex Eval (Vec<3> x) const
770
- {
771
- if (sh.Order() < 0) return 0;
772
-
773
- Vector<Complex> radial(sh.Order()+1);
774
- Vector<Complex> shvals(sh.Order()+1);
775
-
776
- RADIAL::Eval(sh.Order(), kappa*L2Norm(x), scale, radial);
777
- sh.EvalOrders (x, shvals);
778
-
779
- Complex sum = 0;
780
- for (int i = 0; i <= sh.Order(); i++)
781
- sum += shvals(i) * radial(i);
782
-
783
- return sum;
784
- }
785
-
786
- void AddCharge (Vec<3> x, Complex c)
787
- {
788
- if constexpr (!std::is_same<RADIAL,MPSingular>())
789
- throw Exception("AddCharge assumes singular MP");
790
-
791
- // static Timer t("mptool AddCharge"); RegionTimer rg(t);
792
-
793
- if (L2Norm(x) < 1e-10)
794
- {
795
- sh.Coef(0,0) += c * Complex(0,1)*kappa/sqrt(4*M_PI);
796
- return;
797
- }
798
-
799
- // cout << "add charge, kappa rho = " << kappa*L2Norm(x) << ", order = " << sh.Order() << endl;
800
-
801
- Vector<Complex> radial(sh.Order()+1);
802
- Vector<Complex> sh_shapes(sqr (sh.Order()+1));
803
-
804
- RADIAL::Eval(sh.Order(), kappa*L2Norm(x), 1.0/scale, radial);
805
- // cout << "radial = " << radial << endl;
806
- sh.Calc(x, sh_shapes);
807
-
808
- for (int i = 0; i <= sh.Order(); i++)
809
- {
810
- IntRange r(sqr(i), sqr(i+1));
811
- sh.Coefs().Range(r) += c * Complex(0,1)*kappa * radial(i).real()*Conj(sh_shapes.Range(r));
812
- }
813
- }
269
+ Complex Eval (Vec<3> x) const;
814
270
 
271
+ void AddCharge (Vec<3> x, Complex c);
272
+ void AddDipole (Vec<3> x, Vec<3> d, Complex c);
273
+
815
274
 
816
- void AddDipole (Vec<3> x, Vec<3> d, Complex c)
817
- {
818
- // static Timer t("mptool AddDipole"); RegionTimer rg(t);
819
- /*
820
- double eps = 1e-4;
821
- AddCharge(x+eps*d, -c/(2*eps));
822
- AddCharge(x-eps*d, c/(2*eps));
823
- return;
824
- */
825
-
826
- if constexpr (!std::is_same<RADIAL,MPSingular>())
827
- throw Exception("AddCharge assumes singular MP");
828
-
829
- /*
830
- // book, formula (2.2.20)
831
- // dipole in origin:
832
- MultiPole<MPSingular> tmp(1, kappa);
833
- tmp.SH().Coef(1,1) += Complex(0,1)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(0)*c;
834
- tmp.SH().Coef(1,-1) += Complex(0,1)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(0)*c;
835
-
836
- tmp.SH().Coef(1,1) += Complex(1,0)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(1)*c;
837
- tmp.SH().Coef(1,-1) -= Complex(1,0)*sqr(kappa)*sh.CalcBmn(-1,1)/(2*sqrt(4*M_PI)) * d(1)*c;
838
-
839
- tmp.SH().Coef(1,0) += -Complex(0,1)*kappa*kappa*sh.CalcAmn(0,0)/sqrt(4*M_PI) *d(2)*c;
840
- tmp.TransformAdd (*this, -x);
841
- */
842
-
843
- MultiPole<MPSingular> tmp(Order(), kappa, Scale());
844
- tmp.AddCharge(x, c);
845
- tmp.SH().DirectionalDiffAdd (kappa*d, this->SH(), Scale());
846
- }
847
-
848
-
849
275
  void ChangeScaleTo (double newscale)
850
276
  {
851
277
  double fac = scale/newscale;
@@ -855,6 +281,19 @@ c
855
281
  scale = newscale;
856
282
  }
857
283
 
284
+ Vector<double> Spectrum (bool scaled) const
285
+ {
286
+ Vector<double> spec(Order()+1);
287
+ double fac = 1;
288
+ for (int n = 0; n <= Order(); n++)
289
+ {
290
+ spec(n) = fac * L2Norm2(sh.CoefsN(n));
291
+ if (!scaled) fac *= sqr(scale);
292
+ }
293
+ return spec;
294
+ }
295
+
296
+
858
297
  template <typename TARGET>
859
298
  void Transform (MultiPole<TARGET> & target, Vec<3> dist) const
860
299
  {
@@ -903,548 +342,8 @@ c
903
342
  target.SH().Coefs() += tmp.SH().Coefs();
904
343
  }
905
344
 
906
- #ifdef VER1
907
345
  template <typename TARGET>
908
- void ShiftZ (double z, MultiPole<TARGET> & target)
909
- {
910
- static Timer t("mptool ShiftZ"+ToString(typeid(RADIAL).name())+ToString(typeid(TARGET).name()));
911
-
912
- RegionTimer rg(t);
913
-
914
- int os = sh.Order();
915
- int ot = target.SH().Order();
916
-
917
- if (os > 100 && ot > 100 && abs(z)*kappa > 0.3*min(os,ot) && is_same<RADIAL,TARGET>())
918
- {
919
- MultiPole<TARGET> tmp {target};
920
- ShiftZ(z/2, tmp);
921
- tmp.ShiftZ(z/2, target);
922
- return;
923
- }
924
-
925
-
926
- target.SH().Coefs()=0.0;
927
-
928
- LocalHeap lh( 16*( (os+ot+1)*(os+1) + (os+1 + ot+1) ) + 8*2*(os+ot+1) + 500);
929
-
930
- FlatMatrix<Complex> trafo(os+ot+1, os+1, lh);
931
- FlatVector<Complex> hv1(os+1, lh), hv2(ot+1, lh);
932
- FlatVector<double> amn(os+ot+1, lh);
933
- FlatVector<double> inv_amn(os+ot+1, lh);
934
-
935
- // trafo = Complex(0.0);
936
-
937
-
938
- double tscale = target.Scale();
939
- double inv_tscale = 1.0/tscale;
940
-
941
-
942
- // (185) from paper 'fast, exact, stable, Gumerov+Duraiswami
943
- // RADIAL::Eval(os+ot, kappa*abs(z), trafo.Col(0));
944
- if (typeid(RADIAL) == typeid(TARGET))
945
- SphericalBessel (os+ot, kappa*abs(z), tscale, trafo.Col(0));
946
- else
947
- SphericalHankel1 (os+ot, kappa*abs(z), inv_tscale, trafo.Col(0));
948
-
949
- /*
950
- if (L2Norm(trafo.Col(0)) > 1e5 || std::isnan(L2Norm(trafo.Col(0))))
951
- {
952
- *testout << "large Hankel: " << L2Norm(trafo.Col(0)) << endl;
953
- *testout << "kappa z = " << kappa*z << ", os = " << os << ", ot = " << ot << endl;
954
- }
955
- */
956
- // if (L2Norm(trafo.Col(0)) > 1e5)
957
- // throw Exception ("z-shift - coefs large");
958
-
959
- if (z < 0)
960
- for (int l = 1; l < trafo.Height(); l+=2) trafo(l,0) *= -1;
961
-
962
- for (int l = 0; l <= os+ot; l++)
963
- trafo(l,0) *= sqrt(2*l+1);
964
-
965
- if (os > 0)
966
- {
967
- for (int l = 1; l < os+ot; l++)
968
- trafo(l,1) = -scale/sh.CalcAmn(0,0) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,0)
969
- -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,0));
970
- trafo(0,1) = -scale*tscale*trafo(1,0);
971
- }
972
-
973
- for (int n = 1; n < os; n++)
974
- {
975
- for (int l = 1; l < os+ot-n; l++)
976
- trafo(l,n+1) = -scale/sh.CalcAmn(0,n) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,n)
977
- -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,n)
978
- -sh.CalcAmn(0,n-1)*scale*trafo(l,n-1));
979
- trafo(0,n+1) = pow(-scale*tscale,n+1)*trafo(n+1,0);
980
- }
981
-
982
- cout << "m = " << 0 << endl
983
- << trafo.Rows(0,ot+1) << endl;
984
-
985
-
986
- for (int n = 0; n <= os; n++)
987
- hv1(n) = sh.Coef(n,0);
988
- hv2 = trafo.Rows(ot+1) * hv1;
989
- for (int n = 0; n <= ot; n++)
990
- target.SH().Coef(n,0) = hv2(n);
991
-
992
-
993
- for (int m = 1; m <= min(os,ot); m++)
994
- {
995
- // fill recursive formula (187)
996
- for (int l = m; l <= os+ot-m; l++)
997
- trafo(l,m) = scale/sh.CalcBmn(-m, m) * (sh.CalcBmn(-m, l)*inv_tscale*trafo(l-1, m-1)
998
- -sh.CalcBmn(m-1,l+1)*tscale*trafo(l+1,m-1));
999
-
1000
-
1001
- /*
1002
- cout << "m = " << m << endl;
1003
- cout << " norm col0 = " << L2Norm(trafo.Col(m).Range(m,os+ot-m+1)) << endl;
1004
- */
1005
-
1006
- for (int l = m-1; l < os+ot-m; l++)
1007
- {
1008
- amn(l) = sh.CalcAmn(m,l);
1009
- inv_amn(l) = scale/amn(l);
1010
- }
1011
-
1012
- double prod = 1;
1013
- for (int n = m; n < os; n++)
1014
- {
1015
- for (int l = m+1; l < os+ot-n; l++)
1016
- trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
1017
- -amn(l-1)*inv_tscale*trafo(l-1,n)
1018
- -amn(n-1)*scale*trafo(l,n-1));
1019
-
1020
- prod *= -scale*tscale;
1021
- trafo(m,n+1) = prod*trafo(n+1,m);
1022
- }
1023
-
1024
- /*
1025
- cout << " norm trafo = "
1026
- << L2Norm(trafo.Rows(m,ot+1).Cols(m,os+1))
1027
- << " ortho " << L2Norm( Trans(trafo.Rows(m,ot+1).Cols(m,os+1))*trafo.Rows(m,ot+1).Cols(m,os+1)
1028
- - Identity(os+1-m)) << endl;
1029
- */
1030
- /*
1031
- *testout << "norm trafo = " << L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) << endl;
1032
- if ( L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) > 1e30)
1033
- {
1034
- *testout << trafo.Rows(m, ot+1).Cols(m,os+1) << endl;
1035
- for (int i = m; i < os+1; i++)
1036
- {
1037
- *testout << "norm col " << i << " = " << L2Norm(trafo.Col(i).Range(m,os+ot-i)) << endl;
1038
- *testout << "col " << i << " = " << trafo.Col(i).Range(m,os+ot-i) << endl;
1039
- }
1040
- throw Exception("large mat");
1041
- }
1042
- */
1043
-
1044
- cout << "m = " << m << endl
1045
- << trafo.Rows(m,ot+1).Cols(m,os+1) << endl;
1046
-
1047
- for (int n = m; n <= os; n++)
1048
- hv1(n) = sh.Coef(n,m);
1049
- hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1050
- for (int n = m; n <= ot; n++)
1051
- target.SH().Coef(n,m) = hv2(n);
1052
-
1053
- for (int n = m; n <= os; n++)
1054
- hv1(n) = sh.Coef(n,-m);
1055
- hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1056
- for (int n = m; n <= ot; n++)
1057
- target.SH().Coef(n,-m) = hv2(n);
1058
- }
1059
- }
1060
- #endif
1061
-
1062
-
1063
- #ifdef VER2
1064
-
1065
- template <typename TARGET>
1066
- void ShiftZ (double z, MultiPole<TARGET> & target)
1067
- {
1068
- static Timer t("mptool ShiftZ"+ToString(typeid(RADIAL).name())+ToString(typeid(TARGET).name()));
1069
- RegionTimer rg(t);
1070
-
1071
- int os = sh.Order();
1072
- int ot = target.SH().Order();
1073
-
1074
- target.SH().Coefs()=0.0;
1075
-
1076
- LocalHeap lh( 16*( (os+ot+1)*(os+1) + (os+1 + ot+1) ) + 8*2*(os+ot+1) + 500);
1077
-
1078
- FlatMatrix<Complex> trafo(os+ot+1, os+1, lh);
1079
- FlatVector<Complex> hv1(os+1, lh), hv2(ot+1, lh);
1080
- FlatVector<double> amn(os+ot+1, lh);
1081
- FlatVector<double> inv_amn(os+ot+1, lh);
1082
-
1083
- // trafo = Complex(0.0);
1084
-
1085
- double tscale = target.Scale();
1086
- double inv_tscale = 1.0/tscale;
1087
-
1088
-
1089
- // (185) from paper 'fast, exact, stable, Gumerov+Duraiswami
1090
- // RADIAL::Eval(os+ot, kappa*abs(z), trafo.Col(0));
1091
- if (typeid(RADIAL) == typeid(TARGET))
1092
- SphericalBessel (os+ot, kappa*abs(z), tscale, trafo.Col(0));
1093
- else
1094
- SphericalHankel1 (os+ot, kappa*abs(z), inv_tscale, trafo.Col(0));
1095
-
1096
- if (z < 0)
1097
- for (int l = 1; l < trafo.Height(); l+=2) trafo(l,0) *= -1;
1098
-
1099
- // for (int l = 0; l <= os+ot; l++)
1100
- // trafo(l,0) *= sqrt(2*l+1);
1101
-
1102
- if (os > 0)
1103
- {
1104
- for (int l = 1; l < os+ot; l++)
1105
- {
1106
- /*
1107
- trafo(l,1) = -scale/sh.CalcAmn(0,0) *
1108
- (sh.CalcAmn(0,l)*tscale*trafo(l+1,0)
1109
- -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,0));
1110
- */
1111
-
1112
- int m = 0, n = 0;
1113
- double fac = ((2*l+1.0)/(2*n+1.0));
1114
- trafo(l,n+1) = -scale/ ( sqrt((n+1+m)*(n+1-m)) * fac) *
1115
- (sqrt( (l+1+m)*(l+1-m)) * tscale * trafo(l+1,n)
1116
- -sqrt( (l+m)*(l-m) ) * inv_tscale * trafo(l-1,n)
1117
- -sqrt( (n+m)*(n-m) ) * fac * scale * trafo(l,n-1));
1118
- }
1119
- trafo(0,1) = -scale*tscale*trafo(1,0);
1120
- }
1121
-
1122
- for (int n = 1; n < os; n++)
1123
- {
1124
- for (int l = 1; l < os+ot-n; l++)
1125
- {
1126
- /*
1127
- trafo(l,n+1) = -scale/sh.CalcAmn(0,n) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,n)
1128
- -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,n)
1129
- -sh.CalcAmn(0,n-1)*scale*trafo(l,n-1));
1130
- */
1131
-
1132
- int m = 0;
1133
- double fac = ((2*l+1.0)/(2*n+1.0));
1134
- trafo(l,n+1) = -scale / ( sqrt((n+1+m)*(n+1-m)) * fac) *
1135
- (sqrt( (l+1+m)*(l+1-m)) * tscale * trafo(l+1,n)
1136
- -sqrt( (l+m)*(l-m) ) * inv_tscale * trafo(l-1,n)
1137
- -sqrt( (n+m)*(n-m) ) * fac * scale * trafo(l,n-1));
1138
- }
1139
- trafo(0,n+1) = pow(-scale*tscale,n+1)*trafo(n+1,0);
1140
- }
1141
-
1142
-
1143
- Matrix<Complex> scaledtrafo(os+ot+1, os+1);
1144
- for (int l = 0; l <= os+ot; l++)
1145
- for (int n = 0; n <= os; n++)
1146
- scaledtrafo(l,n) = trafo(l,n) * sqrt( (2*l+1)*(2*n+1) );
1147
-
1148
- // cout << "m = " << 0 << endl
1149
- // << scaledtrafo.Rows(0,ot+1) << endl;
1150
-
1151
- for (int n = 0; n <= os; n++)
1152
- hv1(n) = sh.Coef(n,0) * sqrt(2*n+1);
1153
- hv2 = trafo.Rows(ot+1) * hv1;
1154
- for (int n = 0; n <= ot; n++)
1155
- target.SH().Coef(n,0) = hv2(n) * sqrt(2*n+1);
1156
-
1157
-
1158
- for (int m = 1; m <= min(os,ot); m++)
1159
- {
1160
- // fill recursive formula (187)
1161
- for (int l = m; l <= os+ot-m; l++)
1162
- {
1163
- trafo(l,m) = scale/sh.CalcBmn(-m, m) *
1164
- (sh.CalcBmn(-m, l)*inv_tscale * trafo(l-1, m-1) * sqrt( (2*l-1)*(2*m-1) )
1165
- -sh.CalcBmn(m-1,l+1)*tscale * trafo(l+1,m-1) * sqrt( (2*l+3)*(2*m-1)) );
1166
- trafo(l,m) /= sqrt( (2*l+1)*(2*m+1) );
1167
- }
1168
-
1169
- cout << "m = " << m << endl;
1170
- cout << " norm col0 = " << L2Norm(trafo.Col(m).Range(m,os+ot-m+1)) << endl;
1171
-
1172
- for (int l = m-1; l < os+ot-m; l++)
1173
- {
1174
- amn(l) = sh.CalcAmn(m,l);
1175
- inv_amn(l) = scale/amn(l);
1176
- }
1177
-
1178
- double prod = 1;
1179
- for (int n = m; n < os; n++)
1180
- {
1181
- for (int l = m+1; l < os+ot-n; l++)
1182
- {
1183
- /*
1184
- trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
1185
- -amn(l-1)*inv_tscale*trafo(l-1,n)
1186
- -amn(n-1)*scale*trafo(l,n-1));
1187
- */
1188
-
1189
-
1190
- double fac = ((2*l+1.0)/(2*n+1.0));
1191
- trafo(l,n+1) = -scale / ( sqrt((n+1+m)*(n+1-m)) * fac) *
1192
- (sqrt( (l+1+m)*(l+1-m)) * tscale * trafo(l+1,n)
1193
- -sqrt( (l+m)*(l-m) ) * inv_tscale * trafo(l-1,n)
1194
- -sqrt( (n+m)*(n-m) ) * fac * scale * trafo(l,n-1));
1195
- }
1196
- prod *= -scale*tscale;
1197
- trafo(m,n+1) = prod*trafo(n+1,m);
1198
- }
1199
-
1200
- double normleft = 0;
1201
- for (int l = m; l <= ot; l++)
1202
- for (int n = m; n <= min(l,os); n++)
1203
- normleft += sqr(abs(trafo(l,n)));
1204
- normleft = sqrt(normleft);
1205
- cout << " norm trafo = "
1206
- << L2Norm(trafo.Rows(m,ot+1).Cols(m,os+1)) << ", normleft = " << normleft << endl;
1207
-
1208
- // << " ortho " << L2Norm( Trans(trafo.Rows(m,ot+1).Cols(m,os+1))*trafo.Rows(m,ot+1).Cols(m,os+1)
1209
- // - Identity(os+1-m)) << endl;
1210
- /*
1211
- *testout << "norm trafo = " << L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) << endl;
1212
- if ( L2Norm(trafo.Rows(m, ot+1).Cols(m,os+1)) > 1e30)
1213
- {
1214
- *testout << trafo.Rows(m, ot+1).Cols(m,os+1) << endl;
1215
- for (int i = m; i < os+1; i++)
1216
- {
1217
- *testout << "norm col " << i << " = " << L2Norm(trafo.Col(i).Range(m,os+ot-i)) << endl;
1218
- *testout << "col " << i << " = " << trafo.Col(i).Range(m,os+ot-i) << endl;
1219
- }
1220
- throw Exception("large mat");
1221
- }
1222
- */
1223
-
1224
-
1225
- /*
1226
- Matrix<Complex> scaledtrafo(os+ot+1, os+1);
1227
- for (int l = 0; l <= os+ot; l++)
1228
- for (int n = 0; n <= os; n++)
1229
- scaledtrafo(l,n) = trafo(l,n) * sqrt( (2*l+1)*(2*n+1) );
1230
-
1231
- cout << "m = " << m << endl
1232
- << scaledtrafo.Rows(m,ot+1).Cols(m,os+1) << endl;
1233
- */
1234
-
1235
- for (int n = m; n <= os; n++)
1236
- hv1(n) = sh.Coef(n,m) * sqrt(2*n+1);
1237
- hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1238
- for (int n = m; n <= ot; n++)
1239
- target.SH().Coef(n,m) = hv2(n)*sqrt(2*n+1);
1240
-
1241
- for (int n = m; n <= os; n++)
1242
- hv1(n) = sh.Coef(n,-m) * sqrt(2*n+1);
1243
- hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1244
- for (int n = m; n <= ot; n++)
1245
- target.SH().Coef(n,-m) = hv2(n) * sqrt(2*n+1);
1246
- }
1247
- }
1248
- #endif
1249
-
1250
-
1251
-
1252
-
1253
- template <typename TARGET>
1254
- void ShiftZ (double z, MultiPole<TARGET> & target)
1255
- {
1256
- static Timer t("mptool ShiftZ"+ToString(typeid(RADIAL).name())+ToString(typeid(TARGET).name()));
1257
- RegionTimer rg(t);
1258
-
1259
- int os = sh.Order();
1260
- int ot = target.SH().Order();
1261
-
1262
- target.SH().Coefs()=0.0;
1263
-
1264
- LocalHeap lh( 32*( (os+ot+1)*(os+ot+1) + (os+1 + ot+1) ) + 8*3*(os+ot+1) + 500);
1265
-
1266
- FlatMatrix<Complex> trafo(os+ot+1, max(os,ot)+1, lh);
1267
- FlatMatrix<Complex> oldtrafo(os+ot+1, max(os,ot)+1, lh);
1268
- FlatVector<Complex> hv1(os+1, lh), hv2(ot+1, lh);
1269
-
1270
- // trafo = Complex(0.0);
1271
-
1272
- double tscale = target.Scale();
1273
- double inv_tscale = 1.0/tscale;
1274
-
1275
- FlatVector<double> amn(os+ot+1, lh);
1276
- FlatVector<double> inv_amn(os+ot+1, lh);
1277
-
1278
- FlatVector<double> powscale(os+1, lh);
1279
- double prod = 1;
1280
- for (int i = 0; i <= os; i++)
1281
- {
1282
- powscale(i) = prod;
1283
- prod *= -scale*tscale;
1284
- }
1285
-
1286
- // (185) from paper 'fast, exact, stable, Gumerov+Duraiswami
1287
- // RADIAL::Eval(os+ot, kappa*abs(z), trafo.Col(0));
1288
- if (typeid(RADIAL) == typeid(TARGET))
1289
- SphericalBessel (os+ot, kappa*abs(z), tscale, trafo.Col(0));
1290
- else
1291
- SphericalHankel1 (os+ot, kappa*abs(z), inv_tscale, trafo.Col(0));
1292
-
1293
- if (z < 0)
1294
- for (int l = 1; l < trafo.Height(); l+=2) trafo(l,0) *= -1;
1295
-
1296
- for (int l = 0; l <= os+ot; l++)
1297
- trafo(l,0) *= sqrt(2*l+1);
1298
-
1299
- // for (int l = 0; l <= os+ot; l++)
1300
- // trafo(l,0) *= sqrt(2*l+1);
1301
-
1302
- if (os > 0)
1303
- {
1304
- for (int l = 1; l < os+ot; l++)
1305
- trafo(l,1) = -scale/sh.CalcAmn(0,0) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,0)
1306
- -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,0));
1307
- trafo(0,1) = -scale*tscale*trafo(1,0);
1308
- }
1309
-
1310
- for (int n = 1; n < trafo.Width()-1; n++)
1311
- {
1312
- for (int l = 1; l < os+ot-n; l++)
1313
- trafo(l,n+1) = -scale/sh.CalcAmn(0,n) * (sh.CalcAmn(0,l)*tscale*trafo(l+1,n)
1314
- -sh.CalcAmn(0,l-1)*inv_tscale*trafo(l-1,n)
1315
- -sh.CalcAmn(0,n-1)*scale*trafo(l,n-1));
1316
- trafo(0,n+1) = pow(-scale*tscale,n+1)*trafo(n+1,0);
1317
- }
1318
-
1319
- for (int n = 0; n <= os; n++)
1320
- hv1(n) = sh.Coef(n,0);
1321
- hv2 = trafo.Rows(ot+1).Cols(os+1) * hv1;
1322
- for (int n = 0; n <= ot; n++)
1323
- target.SH().Coef(n,0) = hv2(n);
1324
-
1325
-
1326
- for (int m = 1; m <= min(os,ot); m++)
1327
- {
1328
-
1329
-
1330
- for (int l = m-1; l < os+ot-m; l++)
1331
- {
1332
- amn(l) = sh.CalcAmn(m,l);
1333
- inv_amn(l) = scale/amn(l);
1334
- }
1335
-
1336
- if (typeid(RADIAL) != typeid(TARGET))
1337
-
1338
- {
1339
- // fill recursive formula (187)
1340
- for (int l = m; l <= os+ot-m; l++)
1341
- trafo(l,m) = scale/sh.CalcBmn(-m, m) * (sh.CalcBmn(-m, l)*inv_tscale*trafo(l-1, m-1)
1342
- -sh.CalcBmn(m-1,l+1)*tscale*trafo(l+1,m-1));
1343
-
1344
- for (int n = m; n < os; n++)
1345
- {
1346
- for (int l = n+1; l < os+ot-n; l++)
1347
- trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
1348
- -amn(l-1)*inv_tscale*trafo(l-1,n)
1349
- -amn(n-1)*scale*trafo(l,n-1));
1350
- }
1351
- }
1352
-
1353
- else
1354
-
1355
- {
1356
- /*
1357
- for (int n = m; n < trafo.Width()-1; n++)
1358
- {
1359
- for (int l = n+1; l < os+ot-n; l++)
1360
- trafo(l,n+1) = -inv_amn(n) * (amn(l)*tscale*trafo(l+1,n)
1361
- -amn(l-1)*inv_tscale*trafo(l-1,n)
1362
- -amn(n-1)*scale*trafo(l,n-1));
1363
- }
1364
- */
1365
-
1366
- trafo.Swap (oldtrafo);
1367
- trafo = 0.0;
1368
-
1369
- // fill recursive formula (187)
1370
- for (int l = m; l <= os+ot-m; l++)
1371
- trafo(l,m) = scale/sh.CalcBmn(-m, m) * (sh.CalcBmn(-m, l)*inv_tscale*oldtrafo(l-1, m-1)
1372
- -sh.CalcBmn(m-1,l+1)*tscale*oldtrafo(l+1,m-1));
1373
-
1374
- for (int n = m; n < trafo.Width()-1; n++)
1375
- {
1376
- // int l = 2*order-n-1;
1377
- int l = trafo.Height()-n-2;
1378
-
1379
- trafo(l,n+1) = scale/sh.CalcBmn(-m,n+1)* (sh.CalcBmn(m-1,n) * scale*trafo(l,n-1)
1380
- - sh.CalcBmn(m-1,l+1)*tscale*oldtrafo(l+1,n)
1381
- + sh.CalcBmn(-m,l) * 1/tscale*oldtrafo(l-1,n) );
1382
-
1383
- trafo(l-1,n) = tscale/amn(l-1) * (amn(l) * tscale*trafo(l+1,n)
1384
- - amn(n-1)* scale*trafo(l,n-1)
1385
- + amn(n)* 1/scale*trafo(l,n+1));
1386
- }
1387
-
1388
- // the same thing 1 row up
1389
- for (int n = m; n < trafo.Width()-2; n++)
1390
- {
1391
- // int l = 2*order-n-2;
1392
- int l = trafo.Height()-n-3;
1393
-
1394
- trafo(l,n+1) = scale/sh.CalcBmn(-m,n+1)* (sh.CalcBmn(m-1,n) * scale*trafo(l,n-1)
1395
- - sh.CalcBmn(m-1,l+1) * tscale* oldtrafo(l+1,n)
1396
- + sh.CalcBmn(-m,l) * 1/tscale* oldtrafo(l-1,n) );
1397
-
1398
- trafo(l-1,n) = tscale/amn(l-1) * (amn(l) * tscale*trafo(l+1,n)
1399
- -amn(n-1)* scale*trafo(l,n-1) +
1400
- amn(n) * 1/scale*trafo(l,n+1)) ;
1401
- }
1402
-
1403
-
1404
- // for (int l = 2*order; l >= m; l--)
1405
- // for (int n = m+1; n < min(2*order-l,l); n++)
1406
- for (int l = trafo.Height()-1; l >= m; l--)
1407
- for (int n = m+1; n < min<int>(trafo.Height()-1-l,l); n++)
1408
- {
1409
- trafo(l-1,n) = tscale/amn(l-1)* ( amn(l) * tscale*trafo(l+1,n)
1410
- -amn(n-1)* scale*trafo(l,n-1)
1411
- +amn(n) * 1/scale*trafo(l,n+1)) ;
1412
- }
1413
- }
1414
-
1415
-
1416
- /*
1417
- cout << "m = " << m << endl
1418
- << trafo << endl;
1419
- */
1420
- for (int n = m; n < os; n++)
1421
- for (int l = n+1; l <= os; l++)
1422
- trafo(n,l) = powscale(l-n) * trafo(l,n);
1423
- // trafo(n,l) = pow(-scale*tscale, l-n) * trafo(l,n);
1424
-
1425
- /*
1426
- cout << " norm trafo = "
1427
- << L2Norm(trafo.Rows(m,ot+1).Cols(m,os+1)) << endl;
1428
- */
1429
-
1430
- for (int n = m; n <= os; n++)
1431
- hv1(n) = sh.Coef(n,m);
1432
- hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1433
- for (int n = m; n <= ot; n++)
1434
- target.SH().Coef(n,m) = hv2(n);
1435
-
1436
- for (int n = m; n <= os; n++)
1437
- hv1(n) = sh.Coef(n,-m);
1438
- hv2.Range(m,ot+1) = trafo.Rows(m,ot+1).Cols(m,os+1) * hv1.Range(m,os+1);
1439
- for (int n = m; n <= ot; n++)
1440
- target.SH().Coef(n,-m) = hv2(n);
1441
- }
1442
- }
1443
-
1444
-
1445
-
1446
-
1447
-
346
+ void ShiftZ (double z, MultiPole<TARGET> & target);
1448
347
 
1449
348
  };
1450
349
 
@@ -1475,7 +374,7 @@ c
1475
374
  int total_sources;
1476
375
 
1477
376
  Node (Vec<3> acenter, double ar, int alevel, int order, double kappa)
1478
- : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, min(1.0, 1*r*kappa))
377
+ : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, min(1.0, r*kappa))
1479
378
  // : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, 1.0)
1480
379
  {
1481
380
  // cout << "singml, add node, level = " << level << endl;
@@ -1754,7 +653,7 @@ c
1754
653
  }
1755
654
 
1756
655
 
1757
- class RegularMLMultiPole
656
+ class NGS_DLL_HEADER RegularMLMultiPole
1758
657
  {
1759
658
  static Array<size_t> nodes_on_level;
1760
659
 
@@ -2076,11 +975,22 @@ c
2076
975
 
2077
976
  };
2078
977
 
2079
- Array<size_t> RegularMLMultiPole::nodes_on_level(100);
2080
- Array<size_t> SingularMLMultiPole::nodes_on_level(100);
2081
978
 
979
+ inline ostream & operator<< (ostream & ost, const RegularMLMultiPole & mlmp)
980
+ {
981
+ // mlmp.Print(ost);
982
+ ost << "RegularMLMultiPole" << endl;
983
+ return ost;
984
+ }
985
+
986
+
987
+
988
+
989
+
990
+
2082
991
  // ******************** Coefficient Functions *********************
2083
992
 
993
+
2084
994
  class SphericalHarmonicsCF : public CoefficientFunction
2085
995
  {
2086
996
  SphericalHarmonics sh;
@@ -2166,20 +1076,20 @@ c
2166
1076
 
2167
1077
  class RegularMLMultiPoleCF : public CoefficientFunction
2168
1078
  {
2169
- RegularMLMultiPole mlmp;
1079
+ shared_ptr<RegularMLMultiPole> mlmp;
2170
1080
  public:
2171
1081
  RegularMLMultiPoleCF (shared_ptr<SingularMLMultiPoleCF> asingmp, Vec<3> center, double r, int order)
2172
- : CoefficientFunction(1, true), mlmp(asingmp->MLMP(), center, r, order) { }
1082
+ : CoefficientFunction(1, true), mlmp{make_shared<RegularMLMultiPole>(asingmp->MLMP(), center, r, order)} { }
2173
1083
 
2174
1084
  virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
2175
1085
  { throw Exception("real eval not available"); }
2176
1086
 
2177
1087
  virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
2178
1088
  {
2179
- values(0) = mlmp.Evaluate(mip.GetPoint());
1089
+ values(0) = mlmp->Evaluate(mip.GetPoint());
2180
1090
  }
2181
1091
 
2182
- RegularMLMultiPole & MLMP() { return mlmp; }
1092
+ shared_ptr<RegularMLMultiPole> MLMP() { return mlmp; }
2183
1093
  };
2184
1094
 
2185
1095