ngsolve 6.2.2501.post83.dev1__cp310-cp310-win_amd64.whl → 6.2.2503__cp310-cp310-win_amd64.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 (52) hide show
  1. netgen/include/facetfespace.hpp +2 -0
  2. netgen/include/fespace.hpp +4 -2
  3. netgen/include/intrules_SauterSchwab.hpp +25 -0
  4. netgen/include/mptools.hpp +380 -95
  5. netgen/include/ngblas.hpp +14 -0
  6. netgen/include/potentialtools.hpp +20 -0
  7. netgen/include/prolongation.hpp +143 -1
  8. netgen/include/python_ngstd.hpp +1 -0
  9. netgen/include/sparsecholesky.hpp +1 -1
  10. netgen/include/sparsematrix_impl.hpp +71 -5
  11. netgen/include/tangentialfacetfespace.hpp +7 -22
  12. netgen/include/tensor.hpp +1 -1
  13. netgen/lib/libngsolve.lib +0 -0
  14. netgen/libngsolve.dll +0 -0
  15. ngsolve/cmake/NGSolveConfig.cmake +5 -5
  16. ngsolve/cmake/ngsolve-targets.cmake +9 -2
  17. ngsolve/config/config.py +6 -6
  18. ngsolve/ngslib.pyd +0 -0
  19. {ngsolve-6.2.2501.post83.dev1.dist-info → ngsolve-6.2.2503.dist-info}/METADATA +2 -2
  20. {ngsolve-6.2.2501.post83.dev1.dist-info → ngsolve-6.2.2503.dist-info}/RECORD +52 -50
  21. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/Scripts/ngsolve.tcl +0 -0
  22. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/beam.geo +0 -0
  23. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/beam.vol +0 -0
  24. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/chip.in2d +0 -0
  25. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/chip.vol +0 -0
  26. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/coil.geo +0 -0
  27. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/coil.vol +0 -0
  28. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/coilshield.geo +0 -0
  29. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/coilshield.vol +0 -0
  30. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/cube.geo +0 -0
  31. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/cube.vol +0 -0
  32. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d10_DGdoubleglazing.pde +0 -0
  33. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d11_chip_nitsche.pde +0 -0
  34. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d1_square.pde +0 -0
  35. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d2_chip.pde +0 -0
  36. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d3_helmholtz.pde +0 -0
  37. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d4_cube.pde +0 -0
  38. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d5_beam.pde +0 -0
  39. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d6_shaft.pde +0 -0
  40. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d7_coil.pde +0 -0
  41. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d8_coilshield.pde +0 -0
  42. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/d9_hybridDG.pde +0 -0
  43. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/doubleglazing.in2d +0 -0
  44. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/doubleglazing.vol +0 -0
  45. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/piezo2d40round4.vol.gz +0 -0
  46. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/shaft.geo +0 -0
  47. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/shaft.vol +0 -0
  48. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/square.in2d +0 -0
  49. {ngsolve-6.2.2501.post83.dev1.data → ngsolve-6.2.2503.data}/data/share/ngsolve/square.vol +0 -0
  50. {ngsolve-6.2.2501.post83.dev1.dist-info → ngsolve-6.2.2503.dist-info}/LICENSE +0 -0
  51. {ngsolve-6.2.2501.post83.dev1.dist-info → ngsolve-6.2.2503.dist-info}/WHEEL +0 -0
  52. {ngsolve-6.2.2501.post83.dev1.dist-info → ngsolve-6.2.2503.dist-info}/top_level.txt +0 -0
@@ -10,27 +10,32 @@
10
10
  #include <coefficient.hpp>
11
11
  #include <recursive_pol.hpp>
12
12
 
13
- namespace ngfem
14
- {
15
13
 
14
+ namespace ngcomp
15
+ {
16
+ class Region;
17
+ }
16
18
 
19
+ namespace ngsbem
20
+ {
21
+ using namespace ngfem;
17
22
 
23
+
24
+ template <typename entry_type = Complex>
18
25
  class NGS_DLL_HEADER SphericalHarmonics
19
26
  {
20
27
  int order;
21
- Vector<Complex> coefs;
28
+ Vector<entry_type> coefs;
22
29
 
23
30
  public:
24
31
  SphericalHarmonics (int aorder)
25
32
  : order(aorder), coefs(sqr(order+1)) { coefs=0.0; }
26
33
 
27
34
  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
- }
35
+ FlatVector<entry_type> Coefs() const { return coefs; }
36
+
37
+ entry_type & Coef(int n, int m) { return coefs(n*(n+1) + m); }
38
+ entry_type Coef(int n, int m) const { return coefs(n*(n+1) + m); }
34
39
 
35
40
  auto CoefsN (int n) const
36
41
  {
@@ -53,29 +58,29 @@ namespace ngfem
53
58
  return { theta, phi };
54
59
  }
55
60
 
56
- Complex Eval (Vec<3> x) const
61
+ entry_type Eval (Vec<3> x) const
57
62
  {
58
63
  auto [theta, phi] = Polar(x);
59
64
  return Eval(theta, phi);
60
65
  }
61
66
 
62
- Complex Eval (double theta, double phi) const;
67
+ entry_type Eval (double theta, double phi) const;
63
68
 
64
- Complex EvalOrder (int n, Vec<3> x) const
69
+ entry_type EvalOrder (int n, Vec<3> x) const
65
70
  {
66
71
  auto [theta, phi] = Polar (x);
67
72
  return EvalOrder(n, theta, phi);
68
73
  }
69
74
 
70
- Complex EvalOrder (int n, double theta, double phi) const;
75
+ entry_type EvalOrder (int n, double theta, double phi) const;
71
76
 
72
- void EvalOrders (Vec<3> x, FlatVector<Complex> vals) const
77
+ void EvalOrders (Vec<3> x, FlatVector<entry_type> vals) const
73
78
  {
74
79
  auto [theta, phi] = Polar(x);
75
80
  return EvalOrders(theta, phi, vals);
76
81
  }
77
82
 
78
- void EvalOrders (double theta, double phi, FlatVector<Complex> vals) const;
83
+ void EvalOrders (double theta, double phi, FlatVector<entry_type> vals) const;
79
84
 
80
85
  void Calc (Vec<3> x, FlatVector<Complex> shapes);
81
86
 
@@ -106,7 +111,7 @@ namespace ngfem
106
111
 
107
112
  // Nail A. Gumerov and Ramani Duraiswami book, formula (2.2.12)
108
113
  // add directional derivative divided by kappa to res, both multipoles need same scaling
109
- void DirectionalDiffAdd (Vec<3> d, SphericalHarmonics & res, double scale = 1);
114
+ void DirectionalDiffAdd (Vec<3> d, SphericalHarmonics<entry_type> & res, double scale = 1) const;
110
115
 
111
116
  };
112
117
 
@@ -213,48 +218,87 @@ namespace ngfem
213
218
  class MPSingular
214
219
  {
215
220
  public:
221
+ /*
216
222
  template <typename T>
217
223
  static void Eval (int order, double r, double scale, T && values)
218
224
  {
219
225
  SphericalHankel1(order, r, scale, values);
220
226
  }
227
+ */
228
+
229
+ template <typename T>
230
+ static void Eval (int order, double kappa, double r, double rtyp, T && values)
231
+ {
232
+ double scale = Scale(kappa, rtyp);
233
+ SphericalHankel1(order, r*kappa, scale, values);
234
+ }
235
+
236
+ static double Scale (double kappa, double rtyp)
237
+ {
238
+ return min(1.0, rtyp*kappa);
239
+ }
221
240
  };
241
+
242
+
222
243
 
223
244
  // jn
224
245
  class MPRegular
225
246
  {
226
- public:
247
+ public:
248
+ /*
227
249
  template <typename T>
228
250
  static void Eval (int order, double r, double scale, T && values)
229
251
  {
230
252
  SphericalBessel (order, r, 1.0/scale, values);
231
253
  }
254
+ */
255
+
256
+ template <typename T>
257
+ static void Eval (int order, double kappa, double r, double rtyp, T && values)
258
+ {
259
+ double scale = Scale(kappa, rtyp);
260
+ SphericalBessel (order, r*kappa, 1.0/scale, values);
261
+ }
262
+
263
+ static double Scale (double kappa, double rtyp)
264
+ {
265
+ return 1.0/ min(1.0, 0.25*rtyp*kappa);
266
+ }
267
+
232
268
  };
233
269
 
234
270
 
235
271
 
236
272
 
237
- template <typename RADIAL>
273
+ template <typename RADIAL, typename entry_type=Complex>
238
274
  class NGS_DLL_HEADER MultiPole
239
275
  {
240
- SphericalHarmonics sh;
276
+ SphericalHarmonics<entry_type> sh;
241
277
  double kappa;
242
- double scale;
278
+ double rtyp;
279
+ // double scale;
243
280
  public:
281
+ /*
244
282
  MultiPole (int aorder, double akappa, double ascale = 1)
245
283
  : sh(aorder), kappa(akappa), scale(ascale) { }
284
+ */
246
285
 
247
- Complex & Coef(int n, int m) { return sh.Coef(n,m); }
286
+ MultiPole (int aorder, double akappa, double artyp)
287
+ : sh(aorder), kappa(akappa), rtyp(artyp) { }
288
+
289
+
290
+ entry_type & Coef(int n, int m) { return sh.Coef(n,m); }
248
291
  auto & SH() { return sh; }
249
292
  const auto & SH() const { return sh; }
250
293
  double Kappa() const { return kappa; }
251
- double Scale() const { return scale; }
294
+ double Scale() const { return RADIAL::Scale(kappa, rtyp); }
295
+ double RTyp() const { return rtyp; }
252
296
  int Order() const { return sh.Order(); }
253
297
 
254
- MultiPole<RADIAL> Truncate(int neworder) const
298
+ MultiPole Truncate(int neworder) const
255
299
  {
256
300
  if (neworder > sh.Order()) neworder=sh.Order();
257
- MultiPole nmp(neworder, kappa);
301
+ MultiPole nmp(neworder, kappa, rtyp);
258
302
  nmp.sh.Coefs() = sh.Coefs().Range(sqr(neworder+1));
259
303
  return nmp;
260
304
  }
@@ -266,20 +310,34 @@ namespace ngfem
266
310
  return *this;
267
311
  }
268
312
 
269
- Complex Eval (Vec<3> x) const;
313
+ entry_type Eval (Vec<3> x) const;
314
+ entry_type EvalDirectionalDerivative (Vec<3> x, Vec<3> d) const;
270
315
 
271
- void AddCharge (Vec<3> x, Complex c);
272
- void AddDipole (Vec<3> x, Vec<3> d, Complex c);
273
-
316
+ void AddCharge (Vec<3> x, entry_type c);
317
+ void AddDipole (Vec<3> x, Vec<3> d, entry_type c);
318
+ void AddCurrent (Vec<3> ap, Vec<3> ep, Complex j, int num=100);
274
319
 
320
+ /*
275
321
  void ChangeScaleTo (double newscale)
276
322
  {
277
- double fac = scale/newscale;
323
+ double fac = Scale()/newscale;
278
324
  double prod = 1;
279
325
  for (int n = 0; n <= sh.Order(); n++, prod*= fac)
280
326
  sh.CoefsN(n) *= prod;
281
327
  scale = newscale;
282
328
  }
329
+ */
330
+ void ChangeRTypTo (double new_rtyp)
331
+ {
332
+ // double fac = Scale()/newscale;
333
+ double fac = RADIAL::Scale(kappa, rtyp) / RADIAL::Scale(kappa, new_rtyp);
334
+ double prod = 1;
335
+ for (int n = 0; n <= sh.Order(); n++, prod*= fac)
336
+ sh.CoefsN(n) *= prod;
337
+ // scale = newscale;
338
+ rtyp = new_rtyp;
339
+ }
340
+
283
341
 
284
342
  Vector<double> Spectrum (bool scaled) const
285
343
  {
@@ -288,14 +346,14 @@ namespace ngfem
288
346
  for (int n = 0; n <= Order(); n++)
289
347
  {
290
348
  spec(n) = fac * L2Norm2(sh.CoefsN(n));
291
- if (!scaled) fac *= sqr(scale);
349
+ if (!scaled) fac *= sqr(Scale());
292
350
  }
293
351
  return spec;
294
352
  }
295
353
 
296
354
 
297
355
  template <typename TARGET>
298
- void Transform (MultiPole<TARGET> & target, Vec<3> dist) const
356
+ void Transform (MultiPole<TARGET,entry_type> & target, Vec<3> dist) const
299
357
  {
300
358
  if (target.SH().Order() < 0) return;
301
359
  if (SH().Order() < 0)
@@ -321,7 +379,7 @@ namespace ngfem
321
379
  phi = atan2(dist(1), dist(0));
322
380
 
323
381
 
324
- MultiPole<RADIAL> tmp(*this);
382
+ MultiPole<RADIAL,entry_type> tmp(*this);
325
383
  tmp.SH().RotateZ(phi);
326
384
  tmp.SH().RotateY(theta);
327
385
 
@@ -332,18 +390,18 @@ namespace ngfem
332
390
  }
333
391
 
334
392
  template <typename TARGET>
335
- void TransformAdd (MultiPole<TARGET> & target, Vec<3> dist) const
393
+ void TransformAdd (MultiPole<TARGET,entry_type> & target, Vec<3> dist) const
336
394
  {
337
395
  if (SH().Order() < 0) return;
338
396
  if (target.SH().Order() < 0) return;
339
397
 
340
- MultiPole<TARGET> tmp{target};
398
+ MultiPole<TARGET,entry_type> tmp{target};
341
399
  Transform(tmp, dist);
342
400
  target.SH().Coefs() += tmp.SH().Coefs();
343
401
  }
344
402
 
345
403
  template <typename TARGET>
346
- void ShiftZ (double z, MultiPole<TARGET> & target);
404
+ void ShiftZ (double z, MultiPole<TARGET,entry_type> & target);
347
405
 
348
406
  };
349
407
 
@@ -351,12 +409,14 @@ namespace ngfem
351
409
 
352
410
  // ***************** parameters ****************
353
411
 
354
- static int MPOrder (double rho_kappa)
412
+ static constexpr int MPOrder (double rho_kappa)
355
413
  {
356
414
  return max (20, int(2*rho_kappa));
357
415
  }
358
416
  static constexpr int maxdirect = 100;
359
417
 
418
+
419
+ template <typename entry_type=Complex>
360
420
  class SingularMLMultiPole
361
421
  {
362
422
  static Array<size_t> nodes_on_level;
@@ -367,10 +427,11 @@ namespace ngfem
367
427
  double r;
368
428
  int level;
369
429
  std::array<unique_ptr<Node>,8> childs;
370
- MultiPole<MPSingular> mp;
430
+ MultiPole<MPSingular, entry_type> mp;
371
431
 
372
- Array<tuple<Vec<3>, Complex>> charges;
373
- Array<tuple<Vec<3>, Vec<3>, Complex>> dipoles;
432
+ Array<tuple<Vec<3>, entry_type>> charges;
433
+ Array<tuple<Vec<3>, Vec<3>, entry_type>> dipoles;
434
+ Array<tuple<Vec<3>, Vec<3>, Complex,int>> currents;
374
435
  int total_sources;
375
436
 
376
437
  Node (Vec<3> acenter, double ar, int alevel, int order, double kappa)
@@ -397,7 +458,7 @@ namespace ngfem
397
458
  }
398
459
 
399
460
 
400
- void AddCharge (Vec<3> x, Complex c)
461
+ void AddCharge (Vec<3> x, entry_type c)
401
462
  {
402
463
  if (childs[0])
403
464
  {
@@ -422,13 +483,16 @@ namespace ngfem
422
483
  AddCharge (x,c);
423
484
  for (auto [x,d,c] : dipoles)
424
485
  AddDipole (x,d,c);
486
+ for (auto [sp,ep,j,num] : currents)
487
+ AddCurrent (sp,ep,j,num);
425
488
 
426
489
  charges.SetSize0();
427
- dipoles.SetSize0();
490
+ dipoles.SetSize0();
491
+ currents.SetSize0();
428
492
  }
429
493
 
430
494
 
431
- void AddDipole (Vec<3> x, Vec<3> d, Complex c)
495
+ void AddDipole (Vec<3> x, Vec<3> d, entry_type c)
432
496
  {
433
497
  if (childs[0])
434
498
  {
@@ -453,15 +517,70 @@ namespace ngfem
453
517
  AddCharge (x,c);
454
518
  for (auto [x,d,c] : dipoles)
455
519
  AddDipole (x,d,c);
520
+ for (auto [sp,ep,j,num] : currents)
521
+ AddCurrent (sp,ep,j,num);
456
522
 
457
523
  charges.SetSize0();
458
524
  dipoles.SetSize0();
525
+ currents.SetSize0();
459
526
  }
460
527
 
528
+ void AddCurrent (Vec<3> sp, Vec<3> ep, Complex j, int num)
529
+ {
530
+ if (childs[0])
531
+ {
532
+ // split line and send to childs
533
+ Array<double> split;
534
+ split.Append(0);
535
+ for (int i = 0; i < 3; i++)
536
+ if (sp(i) < center(i) != ep(i) < center(i))
537
+ split += (center(i)-sp(i)) / (ep(i)-sp(i)); // segment cuts i-th coordinate plane
538
+ split.Append(1);
539
+ BubbleSort(split);
540
+
541
+ for (int i = 0; i < split.Size()-1; i++)
542
+ if (split[i+1] > split[i])
543
+ {
544
+ Vec<3> spi = sp + split[i]*(ep-sp);
545
+ Vec<3> epi = sp + split[i+1]*(ep-sp);
546
+
547
+ Vec<3> x = 0.5*(spi+epi);
548
+
549
+ int childnum = 0;
550
+ if (x(0) > center(0)) childnum += 1;
551
+ if (x(1) > center(1)) childnum += 2;
552
+ if (x(2) > center(2)) childnum += 4;
553
+ childs[childnum] -> AddCurrent(spi, epi, j, num);
554
+ }
555
+ return;
556
+ }
557
+
558
+ currents.Append (tuple{sp,ep,j,num});
559
+
560
+ // if (currents.Size() < maxdirect || r < 1e-8)
561
+ if (currents.Size() < 4 || r < 1e-8)
562
+ return;
563
+
564
+ CreateChilds();
565
+
566
+ for (auto [x,c] : charges)
567
+ AddCharge (x,c);
568
+ for (auto [x,d,c] : dipoles)
569
+ AddDipole (x,d,c);
570
+ for (auto [sp,ep,j,num] : currents)
571
+ AddCurrent (sp,ep,j,num);
572
+
573
+ charges.SetSize0();
574
+ dipoles.SetSize0();
575
+ currents.SetSize0();
576
+ }
577
+
578
+
579
+
461
580
 
462
- Complex Evaluate(Vec<3> p) const
581
+ entry_type Evaluate(Vec<3> p) const
463
582
  {
464
- Complex sum = 0;
583
+ entry_type sum{0.0};
465
584
  if (childs[0])
466
585
  {
467
586
  for (auto & child : childs)
@@ -471,17 +590,63 @@ namespace ngfem
471
590
 
472
591
  for (auto [x,c] : charges)
473
592
  if (double rho = L2Norm(p-x); rho > 0)
474
- sum += c*(1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) / rho;
593
+ sum += (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) / rho * c;
475
594
 
476
595
  for (auto [x,d,c] : dipoles)
477
596
  if (double rho = L2Norm(p-x); rho > 0)
478
597
  {
479
598
  Vec<3> drhodp = 1.0/rho * (p-x);
480
- Complex dGdrho = c*(1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
599
+ Complex dGdrho = (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
481
600
  (Complex(0, mp.Kappa())/rho - 1.0/sqr(rho));
482
- sum += dGdrho * InnerProduct(drhodp, d);
601
+ sum += dGdrho * InnerProduct(drhodp, d) * c;
483
602
  }
484
603
 
604
+ for (auto [sp,ep,j,num] : currents)
605
+ {
606
+ // should use explizit formula instead ...
607
+
608
+ Vec<3> tau = ep-sp;
609
+ Vec<3> tau_num = 1.0/num * tau;
610
+ for (int i = 0; i < num; i++)
611
+ {
612
+ Vec<3> x = sp+(i+0.5)*tau_num;
613
+
614
+ if (double rho = L2Norm(p-x); rho > 0)
615
+ {
616
+ Vec<3> drhodp = 1.0/rho * (p-x);
617
+ Complex dGdrho = (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
618
+ (Complex(0, mp.Kappa())/rho - 1.0/sqr(rho));
619
+
620
+ if constexpr (std::is_same<entry_type, Vec<3,Complex>>())
621
+ sum += j*dGdrho * Cross(drhodp, tau_num);
622
+ }
623
+ }
624
+ }
625
+
626
+ return sum;
627
+ }
628
+
629
+ entry_type EvaluateDeriv(Vec<3> p, Vec<3> d) const
630
+ {
631
+ entry_type sum{0.0};
632
+ if (childs[0])
633
+ {
634
+ for (auto & child : childs)
635
+ sum += child->EvaluateDeriv(p, d);
636
+ return sum;
637
+ }
638
+
639
+ if (dipoles.Size())
640
+ throw Exception("EvaluateDeriv not implemented for dipoles in SingularMLMultiPole");
641
+
642
+ for (auto [x,c] : charges)
643
+ if (double rho = L2Norm(p-x); rho > 0)
644
+ {
645
+ Vec<3> drhodp = 1.0/rho * (p-x);
646
+ Complex dGdrho = (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
647
+ (Complex(0, mp.Kappa())/rho - 1.0/sqr(rho));
648
+ sum += dGdrho * InnerProduct(drhodp, d) * c;
649
+ }
485
650
  return sum;
486
651
  }
487
652
 
@@ -516,9 +681,9 @@ namespace ngfem
516
681
  }
517
682
  else
518
683
  {
519
- if (charges.Size()+dipoles.Size() == 0)
684
+ if (charges.Size()+dipoles.Size()+currents.Size() == 0)
520
685
  {
521
- mp = MultiPole<MPSingular> (-1, mp.Kappa());
686
+ mp = MultiPole<MPSingular,entry_type> (-1, mp.Kappa(), 1.);
522
687
  return;
523
688
  }
524
689
 
@@ -527,10 +692,13 @@ namespace ngfem
527
692
 
528
693
  for (auto [x,d,c] : dipoles)
529
694
  mp.AddDipole (x-center, d, c);
695
+
696
+ for (auto [sp,ep,j,num] : currents)
697
+ mp.AddCurrent (sp-center, ep-center, j, num);
530
698
  }
531
699
  }
532
700
 
533
- Complex EvaluateMP(Vec<3> p) const
701
+ entry_type EvaluateMP(Vec<3> p) const
534
702
  {
535
703
  if (charges.Size() || dipoles.Size())
536
704
  return Evaluate(p);
@@ -541,22 +709,43 @@ namespace ngfem
541
709
  if (!childs[0]) // || level==1)
542
710
  return Evaluate(p);
543
711
 
544
- Complex sum = 0.0;
712
+ entry_type sum{0.0};
545
713
  for (auto & child : childs)
546
714
  sum += child->EvaluateMP(p);
547
715
  return sum;
548
716
  }
549
-
550
-
551
- void Print (ostream & ost) const
717
+
718
+ entry_type EvaluateMPDeriv(Vec<3> p, Vec<3> d) const
719
+ {
720
+ // cout << "EvaluateMPDeriv Singular, p = " << p << ", d = " << d << ", r = " << r << ", center = " << center << endl;
721
+ // cout << "Norm: " << L2Norm(p-center) << " > " << 3*r << endl;
722
+ // cout << "charges.Size() = " << charges.Size() << ", dipoles.Size() = " << dipoles.Size() << endl;
723
+ if (charges.Size() || dipoles.Size() || !childs[0])
724
+ return EvaluateDeriv(p, d);
725
+
726
+ if (L2Norm(p-center) > 3*r)
727
+ return mp.EvalDirectionalDerivative(p-center, d);
728
+
729
+ entry_type sum{0.0};
730
+ for (auto & child : childs)
731
+ sum += child->EvaluateMPDeriv(p, d);
732
+ return sum;
733
+ }
734
+
735
+ void Print (ostream & ost, size_t childnr = -1) const
552
736
  {
553
- ost << "c = " << center << ", r = " << r << endl;
737
+ if (childnr == -1)
738
+ ost << "c = " << center << ", r = " << r << ", level = " << level << endl;
739
+ else
740
+ ost << "c = " << center << ", r = " << r << ", level = " << level << ", childnr = " << childnr << endl;
554
741
  // for (int i = 0; i < loc_pnts.Size(); i++)
555
742
  for (auto [x,c] : charges)
556
743
  ost << "xi = " << x << ", ci = " << c << endl;
744
+ for (auto [x,d,c] : dipoles)
745
+ ost << "xi = " << x << ", di = " << d << ", ci = " << c << endl;
557
746
 
558
747
  for (int i = 0; i < 8; i++)
559
- if (childs[i]) childs[i] -> Print (ost);
748
+ if (childs[i]) childs[i] -> Print (ost, i);
560
749
  }
561
750
 
562
751
  double Norm () const
@@ -591,16 +780,41 @@ namespace ngfem
591
780
 
592
781
  double Kappa() const { return root.mp.Kappa(); }
593
782
 
594
- void AddCharge(Vec<3> x, Complex c)
783
+ void AddCharge(Vec<3> x, entry_type c)
595
784
  {
596
785
  root.AddCharge(x, c);
597
786
  }
598
787
 
599
- void AddDipole(Vec<3> x, Vec<3> d, Complex c)
788
+ void AddDipole(Vec<3> x, Vec<3> d, entry_type c)
600
789
  {
601
790
  root.AddDipole(x, d, c);
602
791
  }
603
792
 
793
+ void AddCurrent (Vec<3> sp, Vec<3> ep, Complex j, int num)
794
+ {
795
+ if constexpr (!std::is_same<entry_type, Vec<3,Complex>>())
796
+ throw Exception("AddCurrent needs a singular vectorial MP");
797
+
798
+ root.AddCurrent (sp, ep, j, num);
799
+ /*
800
+ // for testing
801
+ Vec<3> tau = ep-sp;
802
+ Vec<3> tau_num = 1.0/num * tau;
803
+ for (int i = 0; i < num; i++)
804
+ {
805
+ for (int k = 0; k < 3; k++)
806
+ {
807
+ Vec<3> ek{0.0}; ek(k) = 1;
808
+ Vec<3> cp = Cross(tau, ek);
809
+ Vec<3,Complex> source{0.0};
810
+ source(k) = j/double(num);
811
+ if constexpr (std::is_same<entry_type, Vec<3,Complex>>())
812
+ root.AddDipole (sp+(i+0.5)*tau_num, cp, source);
813
+ }
814
+ }
815
+ */
816
+ }
817
+
604
818
  void Print (ostream & ost) const
605
819
  {
606
820
  root.Print(ost);
@@ -634,7 +848,7 @@ namespace ngfem
634
848
  havemp = true;
635
849
  }
636
850
 
637
- Complex Evaluate (Vec<3> p) const
851
+ entry_type Evaluate (Vec<3> p) const
638
852
  {
639
853
  if (havemp)
640
854
  return root.EvaluateMP(p);
@@ -642,17 +856,20 @@ namespace ngfem
642
856
  return root.Evaluate(p);
643
857
  }
644
858
 
859
+ template <typename entry_type2>
645
860
  friend class RegularMLMultiPole;
646
861
  };
647
862
 
648
863
 
649
- inline ostream & operator<< (ostream & ost, const SingularMLMultiPole & mlmp)
864
+ template <typename entry_type>
865
+ inline ostream & operator<< (ostream & ost, const SingularMLMultiPole<entry_type> & mlmp)
650
866
  {
651
867
  mlmp.Print(ost);
652
868
  return ost;
653
869
  }
654
870
 
655
871
 
872
+ template <typename elem_type=Complex>
656
873
  class NGS_DLL_HEADER RegularMLMultiPole
657
874
  {
658
875
  static Array<size_t> nodes_on_level;
@@ -663,11 +880,11 @@ namespace ngfem
663
880
  double r;
664
881
  int level;
665
882
  std::array<unique_ptr<Node>,8> childs;
666
- MultiPole<MPRegular> mp;
883
+ MultiPole<MPRegular,elem_type> mp;
667
884
  Array<Vec<3>> targets;
668
885
  int total_targets;
669
886
 
670
- Array<const SingularMLMultiPole::Node*> singnodes;
887
+ Array<const typename SingularMLMultiPole<elem_type>::Node*> singnodes;
671
888
 
672
889
  Node (Vec<3> acenter, double ar, int alevel, int order, double kappa)
673
890
  : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, 1.0/min(1.0, 0.25*r*kappa))
@@ -692,7 +909,7 @@ namespace ngfem
692
909
  }
693
910
  }
694
911
 
695
- void AddSingularNode (const SingularMLMultiPole::Node & singnode, bool allow_refine)
912
+ void AddSingularNode (const typename SingularMLMultiPole<elem_type>::Node & singnode, bool allow_refine)
696
913
  {
697
914
  if (mp.SH().Order() < 0) return;
698
915
  if (singnode.mp.SH().Order() < 0) return;
@@ -781,15 +998,15 @@ namespace ngfem
781
998
  mp.TransformAdd (ch->mp, ch->center-center);
782
999
  ch->LocalizeExpansion(allow_refine);
783
1000
  }
784
- mp = MultiPole<MPRegular>(-1, mp.Kappa());
1001
+ mp = MultiPole<MPRegular,elem_type>(-1, mp.Kappa(), 1.);
785
1002
  //mp.SH().Coefs()=0.0;
786
1003
  }
787
1004
  }
788
1005
 
789
- Complex Evaluate (Vec<3> p) const
1006
+ elem_type Evaluate (Vec<3> p) const
790
1007
  {
791
1008
  // *testout << "eval p = " << p << ", level = " << level << ", center = " << center << ", r = " << r << endl;
792
- Complex sum = 0.0;
1009
+ elem_type sum{0.0};
793
1010
  /*
794
1011
  if (childs[0])
795
1012
  {
@@ -817,6 +1034,28 @@ namespace ngfem
817
1034
  return sum;
818
1035
  }
819
1036
 
1037
+ elem_type EvaluateDirectionalDerivative (Vec<3> p, Vec<3> d) const
1038
+ {
1039
+ elem_type sum{0.0};
1040
+ // cout << "EvaluateDirectionalDerivative RegularMLMP, r = " << r << ", level = " << level << ", center = " << center << endl;
1041
+ // cout << "Singnodes: " << singnodes.Size() << ", childs: " << childs[0] << endl;
1042
+
1043
+ int childnum = 0;
1044
+ if (p(0) > center(0)) childnum += 1;
1045
+ if (p(1) > center(1)) childnum += 2;
1046
+ if (p(2) > center(2)) childnum += 4;
1047
+ if (childs[childnum])
1048
+ sum = childs[childnum]->EvaluateDirectionalDerivative(p, d);
1049
+ else
1050
+ sum = mp.EvalDirectionalDerivative(p-center, d);
1051
+
1052
+ static Timer t("mptool direct evaluate deriv"); RegionTimer r(t);
1053
+ for (auto sn : singnodes)
1054
+ sum += sn->EvaluateMPDeriv(p, d);
1055
+
1056
+ return sum;
1057
+ }
1058
+
820
1059
  double Norm() const
821
1060
  {
822
1061
  double norm = L2Norm(mp.SH().Coefs());
@@ -883,16 +1122,30 @@ namespace ngfem
883
1122
  }
884
1123
 
885
1124
  if (total_targets == 0)
886
- mp = MultiPole<MPRegular>(-1, mp.Kappa());
1125
+ mp = MultiPole<MPRegular,elem_type>(-1, mp.Kappa(),1.);
887
1126
  }
888
1127
 
1128
+
1129
+ void Print (ostream & ost, size_t childnr = -1) const
1130
+ {
1131
+ if (childnr == -1)
1132
+ ost << "c = " << center << ", r = " << r << ", level = " << level << endl;
1133
+ else
1134
+ ost << "c = " << center << ", r = " << r << ", level = " << level << ", childnr = " << childnr << endl;
1135
+ for (auto x : targets)
1136
+ ost << "xi = " << x << endl;
1137
+
1138
+ for (int i = 0; i < 8; i++)
1139
+ if (childs[i]) childs[i] -> Print (ost, i);
1140
+ }
1141
+
889
1142
  };
890
1143
 
891
1144
  Node root;
892
- shared_ptr<SingularMLMultiPole> singmp;
1145
+ shared_ptr<SingularMLMultiPole<elem_type>> singmp;
893
1146
 
894
1147
  public:
895
- RegularMLMultiPole (shared_ptr<SingularMLMultiPole> asingmp, Vec<3> center, double r, int order)
1148
+ RegularMLMultiPole (shared_ptr<SingularMLMultiPole<elem_type>> asingmp, Vec<3> center, double r, int order)
896
1149
  : root(center, r, 0, order, asingmp->Kappa()), singmp(asingmp)
897
1150
  {
898
1151
  if (!singmp->havemp) throw Exception("first call Calc for singular MP");
@@ -934,7 +1187,7 @@ namespace ngfem
934
1187
  root.AddTarget (t);
935
1188
  }
936
1189
 
937
- void CalcMP(shared_ptr<SingularMLMultiPole> asingmp)
1190
+ void CalcMP(shared_ptr<SingularMLMultiPole<elem_type>> asingmp)
938
1191
  {
939
1192
  singmp = asingmp;
940
1193
 
@@ -955,6 +1208,11 @@ namespace ngfem
955
1208
  root.LocalizeExpansion(false);
956
1209
  }
957
1210
 
1211
+ void Print (ostream & ost) const
1212
+ {
1213
+ root.Print(ost);
1214
+ }
1215
+
958
1216
  double Norm() const
959
1217
  {
960
1218
  return root.Norm();
@@ -965,21 +1223,26 @@ namespace ngfem
965
1223
  return root.NumCoefficients();
966
1224
  }
967
1225
 
968
- Complex Evaluate (Vec<3> p) const
1226
+ elem_type Evaluate (Vec<3> p) const
969
1227
  {
970
1228
  // static Timer t("mptool Eval MLMP regular"); RegionTimer r(t);
971
- if (L2Norm(p-root.center) > root.r) return 0.0;
1229
+ if (L2Norm(p-root.center) > root.r) return elem_type{0.0};
972
1230
  return root.Evaluate(p);
973
1231
  }
974
1232
 
975
-
1233
+ elem_type EvaluateDirectionalDerivative (Vec<3> p, Vec<3> d) const
1234
+ {
1235
+ if (L2Norm(p-root.center) > root.r) return elem_type{0.0};
1236
+ return root.EvaluateDirectionalDerivative(p, d);
1237
+ }
1238
+
976
1239
  };
977
-
978
1240
 
979
- inline ostream & operator<< (ostream & ost, const RegularMLMultiPole & mlmp)
1241
+ template <typename elem_type>
1242
+ inline ostream & operator<< (ostream & ost, const RegularMLMultiPole<elem_type> & mlmp)
980
1243
  {
981
- // mlmp.Print(ost);
982
- ost << "RegularMLMultiPole" << endl;
1244
+ mlmp.Print(ost);
1245
+ // ost << "RegularMLMultiPole" << endl;
983
1246
  return ost;
984
1247
  }
985
1248
 
@@ -993,7 +1256,7 @@ namespace ngfem
993
1256
 
994
1257
  class SphericalHarmonicsCF : public CoefficientFunction
995
1258
  {
996
- SphericalHarmonics sh;
1259
+ SphericalHarmonics<Complex> sh;
997
1260
  public:
998
1261
  SphericalHarmonicsCF (int order)
999
1262
  : CoefficientFunction(1, true), sh(order) { }
@@ -1021,16 +1284,19 @@ namespace ngfem
1021
1284
 
1022
1285
 
1023
1286
 
1024
- template <typename RADIAL>
1287
+ template <typename entry_type> class RegularMLMultiPoleCF;
1288
+
1289
+
1290
+ template <typename RADIAL, typename entry_type=Complex>
1025
1291
  class MultiPoleCF : public CoefficientFunction
1026
1292
  {
1027
- MultiPole<RADIAL> mp;
1293
+ MultiPole<RADIAL, entry_type> mp;
1028
1294
  Vec<3> center;
1029
1295
  public:
1030
1296
  MultiPoleCF (int order, double kappa, Vec<3> acenter, double scale = 1)
1031
- : CoefficientFunction(1, true), mp(order, kappa, scale), center(acenter) { }
1297
+ : CoefficientFunction(sizeof(entry_type)/sizeof(Complex), true), mp(order, kappa, scale), center(acenter) { }
1032
1298
 
1033
- Complex & Coef(int n, int m) { return mp.Coef(n,m); }
1299
+ entry_type & Coef(int n, int m) { return mp.Coef(n,m); }
1034
1300
  auto & SH() { return mp.SH(); }
1035
1301
  auto & MP() { return mp; }
1036
1302
  Vec<3> Center() const { return center; }
@@ -1040,56 +1306,75 @@ namespace ngfem
1040
1306
 
1041
1307
  virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
1042
1308
  {
1043
- values(0) = mp.Eval(mip.GetPoint()-center);
1309
+ if constexpr (std::is_same<entry_type, Complex>())
1310
+ values(0) = mp.Eval(mip.GetPoint()-center);
1311
+ else
1312
+ values = mp.Eval(mip.GetPoint()-center);
1044
1313
  }
1045
1314
 
1046
1315
  template <typename TARGET>
1047
- void ShiftZ (double z, MultiPole<TARGET> & target) { mp.ShiftZ(z, target); }
1316
+ void ShiftZ (double z, MultiPole<TARGET, entry_type> & target) { mp.ShiftZ(z, target); }
1048
1317
 
1049
1318
  using CoefficientFunction::Transform;
1050
1319
  template <typename TARGET>
1051
- void Transform (MultiPoleCF<TARGET> & target)
1320
+ void Transform (MultiPoleCF<TARGET, entry_type> & target)
1052
1321
  {
1053
1322
  mp.Transform (target.MP(), target.Center()-center);
1054
1323
  }
1055
1324
  };
1056
1325
 
1057
-
1326
+ template <typename entry_type>
1058
1327
  class SingularMLMultiPoleCF : public CoefficientFunction
1059
1328
  {
1060
- shared_ptr<SingularMLMultiPole> mlmp;
1329
+ shared_ptr<SingularMLMultiPole<entry_type>> mlmp;
1061
1330
  public:
1062
1331
  SingularMLMultiPoleCF (Vec<3> center, double r, int order, double kappa)
1063
- : CoefficientFunction(1, true), mlmp{make_shared<SingularMLMultiPole>(center, r, order, kappa)} { }
1332
+ : CoefficientFunction(sizeof(entry_type)/sizeof(Complex), true), mlmp{make_shared<SingularMLMultiPole<entry_type>>(center, r, order, kappa)} { }
1064
1333
 
1065
1334
  virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
1066
1335
  { throw Exception("real eval not available"); }
1067
1336
 
1068
1337
  virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
1069
1338
  {
1070
- values(0) = mlmp->Evaluate(mip.GetPoint());
1339
+ // values(0) = mlmp->Evaluate(mip.GetPoint());
1340
+
1341
+ if constexpr (std::is_same<entry_type, Complex>())
1342
+ values(0) = mlmp->Evaluate(mip.GetPoint());
1343
+ else
1344
+ values = mlmp->Evaluate(mip.GetPoint());
1345
+
1346
+
1071
1347
  }
1072
1348
 
1073
- shared_ptr<SingularMLMultiPole> MLMP() { return mlmp; }
1349
+ shared_ptr<SingularMLMultiPole<entry_type>> MLMP() const { return mlmp; }
1350
+ shared_ptr<RegularMLMultiPoleCF<entry_type>> CreateRegularExpansion(Vec<3> center, double r) const;
1074
1351
  };
1075
1352
 
1076
1353
 
1354
+ template <typename entry_type>
1077
1355
  class RegularMLMultiPoleCF : public CoefficientFunction
1078
1356
  {
1079
- shared_ptr<RegularMLMultiPole> mlmp;
1357
+ shared_ptr<RegularMLMultiPole<entry_type>> mlmp;
1080
1358
  public:
1081
- RegularMLMultiPoleCF (shared_ptr<SingularMLMultiPoleCF> asingmp, Vec<3> center, double r, int order)
1082
- : CoefficientFunction(1, true), mlmp{make_shared<RegularMLMultiPole>(asingmp->MLMP(), center, r, order)} { }
1359
+ RegularMLMultiPoleCF (shared_ptr<SingularMLMultiPoleCF<entry_type>> asingmp, Vec<3> center, double r, int order)
1360
+ : CoefficientFunction(sizeof(entry_type)/sizeof(Complex), true), mlmp{make_shared<RegularMLMultiPole<entry_type>>(asingmp->MLMP(), center, r, order)} { }
1361
+ RegularMLMultiPoleCF (shared_ptr<SingularMLMultiPole<entry_type>> asingmp, Vec<3> center, double r, int order)
1362
+ : CoefficientFunction(sizeof(entry_type)/sizeof(Complex), true), mlmp{make_shared<RegularMLMultiPole<entry_type>>(asingmp, center, r, order)} { }
1083
1363
 
1084
1364
  virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
1085
1365
  { throw Exception("real eval not available"); }
1086
1366
 
1087
1367
  virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
1088
1368
  {
1089
- values(0) = mlmp->Evaluate(mip.GetPoint());
1369
+ // values(0) = mlmp->Evaluate(mip.GetPoint());
1370
+
1371
+ if constexpr (std::is_same<entry_type, Complex>())
1372
+ values(0) = mlmp->Evaluate(mip.GetPoint());
1373
+ else
1374
+ values = mlmp->Evaluate(mip.GetPoint());
1090
1375
  }
1091
1376
 
1092
- shared_ptr<RegularMLMultiPole> MLMP() { return mlmp; }
1377
+ shared_ptr<RegularMLMultiPole<entry_type>> MLMP() { return mlmp; }
1093
1378
  };
1094
1379
 
1095
1380