ngsolve 6.2.2501.post70.dev1__cp313-cp313-win_amd64.whl → 6.2.2502__cp313-cp313-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 (53) hide show
  1. netgen/include/contact.hpp +2 -2
  2. netgen/include/facetfespace.hpp +2 -0
  3. netgen/include/fespace.hpp +2 -1
  4. netgen/include/mptools.hpp +307 -86
  5. netgen/include/ngblas.hpp +14 -0
  6. netgen/include/periodic.hpp +4 -0
  7. netgen/include/prolongation.hpp +20 -1
  8. netgen/include/python_ngstd.hpp +1 -0
  9. netgen/include/sparsecholesky.hpp +1 -1
  10. netgen/include/tensor.hpp +1 -1
  11. netgen/include/vector.hpp +1 -1
  12. netgen/lib/libngsolve.lib +0 -0
  13. netgen/libngsolve.dll +0 -0
  14. netgen/ngscxx.bat +1 -1
  15. netgen/ngsld.bat +1 -1
  16. ngsolve/cmake/NGSolveConfig.cmake +2 -2
  17. ngsolve/config/config.py +9 -9
  18. ngsolve/ngslib.lib +0 -0
  19. ngsolve/ngslib.pyd +0 -0
  20. {ngsolve-6.2.2501.post70.dev1.dist-info → ngsolve-6.2.2502.dist-info}/METADATA +2 -2
  21. {ngsolve-6.2.2501.post70.dev1.dist-info → ngsolve-6.2.2502.dist-info}/RECORD +53 -53
  22. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/Scripts/ngsolve.tcl +0 -0
  23. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/beam.geo +0 -0
  24. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/beam.vol +0 -0
  25. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/chip.in2d +0 -0
  26. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/chip.vol +0 -0
  27. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/coil.geo +0 -0
  28. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/coil.vol +0 -0
  29. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/coilshield.geo +0 -0
  30. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/coilshield.vol +0 -0
  31. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/cube.geo +0 -0
  32. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/cube.vol +0 -0
  33. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d10_DGdoubleglazing.pde +0 -0
  34. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d11_chip_nitsche.pde +0 -0
  35. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d1_square.pde +0 -0
  36. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d2_chip.pde +0 -0
  37. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d3_helmholtz.pde +0 -0
  38. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d4_cube.pde +0 -0
  39. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d5_beam.pde +0 -0
  40. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d6_shaft.pde +0 -0
  41. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d7_coil.pde +0 -0
  42. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d8_coilshield.pde +0 -0
  43. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/d9_hybridDG.pde +0 -0
  44. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/doubleglazing.in2d +0 -0
  45. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/doubleglazing.vol +0 -0
  46. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/piezo2d40round4.vol.gz +0 -0
  47. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/shaft.geo +0 -0
  48. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/shaft.vol +0 -0
  49. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/square.in2d +0 -0
  50. {ngsolve-6.2.2501.post70.dev1.data → ngsolve-6.2.2502.data}/data/share/ngsolve/square.vol +0 -0
  51. {ngsolve-6.2.2501.post70.dev1.dist-info → ngsolve-6.2.2502.dist-info}/WHEEL +0 -0
  52. {ngsolve-6.2.2501.post70.dev1.dist-info → ngsolve-6.2.2502.dist-info}/licenses/LICENSE +0 -0
  53. {ngsolve-6.2.2501.post70.dev1.dist-info → ngsolve-6.2.2502.dist-info}/top_level.txt +0 -0
@@ -14,23 +14,21 @@ namespace ngfem
14
14
  {
15
15
 
16
16
 
17
-
17
+ template <typename entry_type = Complex>
18
18
  class NGS_DLL_HEADER SphericalHarmonics
19
19
  {
20
20
  int order;
21
- Vector<Complex> coefs;
21
+ Vector<entry_type> coefs;
22
22
 
23
23
  public:
24
24
  SphericalHarmonics (int aorder)
25
25
  : order(aorder), coefs(sqr(order+1)) { coefs=0.0; }
26
26
 
27
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
- }
28
+ FlatVector<entry_type> Coefs() const { return coefs; }
29
+
30
+ entry_type & Coef(int n, int m) { return coefs(n*(n+1) + m); }
31
+ entry_type Coef(int n, int m) const { return coefs(n*(n+1) + m); }
34
32
 
35
33
  auto CoefsN (int n) const
36
34
  {
@@ -53,29 +51,29 @@ namespace ngfem
53
51
  return { theta, phi };
54
52
  }
55
53
 
56
- Complex Eval (Vec<3> x) const
54
+ entry_type Eval (Vec<3> x) const
57
55
  {
58
56
  auto [theta, phi] = Polar(x);
59
57
  return Eval(theta, phi);
60
58
  }
61
59
 
62
- Complex Eval (double theta, double phi) const;
60
+ entry_type Eval (double theta, double phi) const;
63
61
 
64
- Complex EvalOrder (int n, Vec<3> x) const
62
+ entry_type EvalOrder (int n, Vec<3> x) const
65
63
  {
66
64
  auto [theta, phi] = Polar (x);
67
65
  return EvalOrder(n, theta, phi);
68
66
  }
69
67
 
70
- Complex EvalOrder (int n, double theta, double phi) const;
68
+ entry_type EvalOrder (int n, double theta, double phi) const;
71
69
 
72
- void EvalOrders (Vec<3> x, FlatVector<Complex> vals) const
70
+ void EvalOrders (Vec<3> x, FlatVector<entry_type> vals) const
73
71
  {
74
72
  auto [theta, phi] = Polar(x);
75
73
  return EvalOrders(theta, phi, vals);
76
74
  }
77
75
 
78
- void EvalOrders (double theta, double phi, FlatVector<Complex> vals) const;
76
+ void EvalOrders (double theta, double phi, FlatVector<entry_type> vals) const;
79
77
 
80
78
  void Calc (Vec<3> x, FlatVector<Complex> shapes);
81
79
 
@@ -106,7 +104,7 @@ namespace ngfem
106
104
 
107
105
  // Nail A. Gumerov and Ramani Duraiswami book, formula (2.2.12)
108
106
  // add directional derivative divided by kappa to res, both multipoles need same scaling
109
- void DirectionalDiffAdd (Vec<3> d, SphericalHarmonics & res, double scale = 1);
107
+ void DirectionalDiffAdd (Vec<3> d, SphericalHarmonics<entry_type> & res, double scale = 1) const;
110
108
 
111
109
  };
112
110
 
@@ -162,13 +160,13 @@ namespace ngfem
162
160
  values(i) = (2*i-1)/rho * values(i-1) - values(i-2);
163
161
  */
164
162
 
165
- if (rho < 1e-8)
163
+ if (rho < 1e-100)
166
164
  {
167
165
  values = Complex(0);
168
166
  return;
169
167
  }
170
168
  Vector j(n+1), y(n+1), jp(n+1), yp(n+1);
171
- SBESJY (rho, n, j, y, jp, yp);
169
+ // SBESJY (rho, n, j, y, jp, yp);
172
170
 
173
171
  /*
174
172
  values = j + Complex(0,1) * y;
@@ -234,24 +232,24 @@ namespace ngfem
234
232
 
235
233
 
236
234
 
237
- template <typename RADIAL>
235
+ template <typename RADIAL, typename entry_type=Complex>
238
236
  class NGS_DLL_HEADER MultiPole
239
237
  {
240
- SphericalHarmonics sh;
238
+ SphericalHarmonics<entry_type> sh;
241
239
  double kappa;
242
240
  double scale;
243
241
  public:
244
242
  MultiPole (int aorder, double akappa, double ascale = 1)
245
243
  : sh(aorder), kappa(akappa), scale(ascale) { }
246
244
 
247
- Complex & Coef(int n, int m) { return sh.Coef(n,m); }
245
+ entry_type & Coef(int n, int m) { return sh.Coef(n,m); }
248
246
  auto & SH() { return sh; }
249
247
  const auto & SH() const { return sh; }
250
248
  double Kappa() const { return kappa; }
251
249
  double Scale() const { return scale; }
252
250
  int Order() const { return sh.Order(); }
253
251
 
254
- MultiPole<RADIAL> Truncate(int neworder) const
252
+ MultiPole Truncate(int neworder) const
255
253
  {
256
254
  if (neworder > sh.Order()) neworder=sh.Order();
257
255
  MultiPole nmp(neworder, kappa);
@@ -266,10 +264,12 @@ namespace ngfem
266
264
  return *this;
267
265
  }
268
266
 
269
- Complex Eval (Vec<3> x) const;
267
+ entry_type Eval (Vec<3> x) const;
268
+ entry_type EvalDirectionalDerivative (Vec<3> x, Vec<3> d) const;
270
269
 
271
- void AddCharge (Vec<3> x, Complex c);
272
- void AddDipole (Vec<3> x, Vec<3> d, Complex c);
270
+ void AddCharge (Vec<3> x, entry_type c);
271
+ void AddDipole (Vec<3> x, Vec<3> d, entry_type c);
272
+ void AddCurrent (Vec<3> ap, Vec<3> ep, Complex j, int num=100);
273
273
 
274
274
 
275
275
  void ChangeScaleTo (double newscale)
@@ -295,7 +295,7 @@ namespace ngfem
295
295
 
296
296
 
297
297
  template <typename TARGET>
298
- void Transform (MultiPole<TARGET> & target, Vec<3> dist) const
298
+ void Transform (MultiPole<TARGET,entry_type> & target, Vec<3> dist) const
299
299
  {
300
300
  if (target.SH().Order() < 0) return;
301
301
  if (SH().Order() < 0)
@@ -321,7 +321,7 @@ namespace ngfem
321
321
  phi = atan2(dist(1), dist(0));
322
322
 
323
323
 
324
- MultiPole<RADIAL> tmp(*this);
324
+ MultiPole<RADIAL,entry_type> tmp(*this);
325
325
  tmp.SH().RotateZ(phi);
326
326
  tmp.SH().RotateY(theta);
327
327
 
@@ -332,18 +332,18 @@ namespace ngfem
332
332
  }
333
333
 
334
334
  template <typename TARGET>
335
- void TransformAdd (MultiPole<TARGET> & target, Vec<3> dist) const
335
+ void TransformAdd (MultiPole<TARGET,entry_type> & target, Vec<3> dist) const
336
336
  {
337
337
  if (SH().Order() < 0) return;
338
338
  if (target.SH().Order() < 0) return;
339
339
 
340
- MultiPole<TARGET> tmp{target};
340
+ MultiPole<TARGET,entry_type> tmp{target};
341
341
  Transform(tmp, dist);
342
342
  target.SH().Coefs() += tmp.SH().Coefs();
343
343
  }
344
344
 
345
345
  template <typename TARGET>
346
- void ShiftZ (double z, MultiPole<TARGET> & target);
346
+ void ShiftZ (double z, MultiPole<TARGET,entry_type> & target);
347
347
 
348
348
  };
349
349
 
@@ -351,12 +351,14 @@ namespace ngfem
351
351
 
352
352
  // ***************** parameters ****************
353
353
 
354
- static int MPOrder (double rho_kappa)
354
+ static constexpr int MPOrder (double rho_kappa)
355
355
  {
356
356
  return max (20, int(2*rho_kappa));
357
357
  }
358
358
  static constexpr int maxdirect = 100;
359
359
 
360
+
361
+ template <typename entry_type=Complex>
360
362
  class SingularMLMultiPole
361
363
  {
362
364
  static Array<size_t> nodes_on_level;
@@ -367,10 +369,11 @@ namespace ngfem
367
369
  double r;
368
370
  int level;
369
371
  std::array<unique_ptr<Node>,8> childs;
370
- MultiPole<MPSingular> mp;
372
+ MultiPole<MPSingular, entry_type> mp;
371
373
 
372
- Array<tuple<Vec<3>, Complex>> charges;
373
- Array<tuple<Vec<3>, Vec<3>, Complex>> dipoles;
374
+ Array<tuple<Vec<3>, entry_type>> charges;
375
+ Array<tuple<Vec<3>, Vec<3>, entry_type>> dipoles;
376
+ Array<tuple<Vec<3>, Vec<3>, Complex,int>> currents;
374
377
  int total_sources;
375
378
 
376
379
  Node (Vec<3> acenter, double ar, int alevel, int order, double kappa)
@@ -397,7 +400,7 @@ namespace ngfem
397
400
  }
398
401
 
399
402
 
400
- void AddCharge (Vec<3> x, Complex c)
403
+ void AddCharge (Vec<3> x, entry_type c)
401
404
  {
402
405
  if (childs[0])
403
406
  {
@@ -422,13 +425,16 @@ namespace ngfem
422
425
  AddCharge (x,c);
423
426
  for (auto [x,d,c] : dipoles)
424
427
  AddDipole (x,d,c);
428
+ for (auto [sp,ep,j,num] : currents)
429
+ AddCurrent (sp,ep,j,num);
425
430
 
426
431
  charges.SetSize0();
427
- dipoles.SetSize0();
432
+ dipoles.SetSize0();
433
+ currents.SetSize0();
428
434
  }
429
435
 
430
436
 
431
- void AddDipole (Vec<3> x, Vec<3> d, Complex c)
437
+ void AddDipole (Vec<3> x, Vec<3> d, entry_type c)
432
438
  {
433
439
  if (childs[0])
434
440
  {
@@ -453,15 +459,70 @@ namespace ngfem
453
459
  AddCharge (x,c);
454
460
  for (auto [x,d,c] : dipoles)
455
461
  AddDipole (x,d,c);
462
+ for (auto [sp,ep,j,num] : currents)
463
+ AddCurrent (sp,ep,j,num);
456
464
 
457
465
  charges.SetSize0();
458
466
  dipoles.SetSize0();
467
+ currents.SetSize0();
468
+ }
469
+
470
+ void AddCurrent (Vec<3> sp, Vec<3> ep, Complex j, int num)
471
+ {
472
+ if (childs[0])
473
+ {
474
+ // split line and send to childs
475
+ Array<double> split;
476
+ split.Append(0);
477
+ for (int i = 0; i < 3; i++)
478
+ if (sp(i) < center(i) != ep(i) < center(i))
479
+ split += (center(i)-sp(i)) / (ep(i)-sp(i)); // segment cuts i-th coordinate plane
480
+ split.Append(1);
481
+ BubbleSort(split);
482
+
483
+ for (int i = 0; i < split.Size()-1; i++)
484
+ if (split[i+1] > split[i])
485
+ {
486
+ Vec<3> spi = sp + split[i]*(ep-sp);
487
+ Vec<3> epi = sp + split[i+1]*(ep-sp);
488
+
489
+ Vec<3> x = 0.5*(spi+epi);
490
+
491
+ int childnum = 0;
492
+ if (x(0) > center(0)) childnum += 1;
493
+ if (x(1) > center(1)) childnum += 2;
494
+ if (x(2) > center(2)) childnum += 4;
495
+ childs[childnum] -> AddCurrent(spi, epi, j, num);
496
+ }
497
+ return;
498
+ }
499
+
500
+ currents.Append (tuple{sp,ep,j,num});
501
+
502
+ // if (currents.Size() < maxdirect || r < 1e-8)
503
+ if (currents.Size() < 4 || r < 1e-8)
504
+ return;
505
+
506
+ CreateChilds();
507
+
508
+ for (auto [x,c] : charges)
509
+ AddCharge (x,c);
510
+ for (auto [x,d,c] : dipoles)
511
+ AddDipole (x,d,c);
512
+ for (auto [sp,ep,j,num] : currents)
513
+ AddCurrent (sp,ep,j,num);
514
+
515
+ charges.SetSize0();
516
+ dipoles.SetSize0();
517
+ currents.SetSize0();
459
518
  }
460
519
 
520
+
461
521
 
462
- Complex Evaluate(Vec<3> p) const
522
+
523
+ entry_type Evaluate(Vec<3> p) const
463
524
  {
464
- Complex sum = 0;
525
+ entry_type sum{0.0};
465
526
  if (childs[0])
466
527
  {
467
528
  for (auto & child : childs)
@@ -471,17 +532,63 @@ namespace ngfem
471
532
 
472
533
  for (auto [x,c] : charges)
473
534
  if (double rho = L2Norm(p-x); rho > 0)
474
- sum += c*(1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) / rho;
535
+ sum += (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) / rho * c;
475
536
 
476
537
  for (auto [x,d,c] : dipoles)
477
538
  if (double rho = L2Norm(p-x); rho > 0)
478
539
  {
479
540
  Vec<3> drhodp = 1.0/rho * (p-x);
480
- Complex dGdrho = c*(1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
541
+ Complex dGdrho = (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
481
542
  (Complex(0, mp.Kappa())/rho - 1.0/sqr(rho));
482
- sum += dGdrho * InnerProduct(drhodp, d);
543
+ sum += dGdrho * InnerProduct(drhodp, d) * c;
483
544
  }
484
545
 
546
+ for (auto [sp,ep,j,num] : currents)
547
+ {
548
+ // should use explizit formula instead ...
549
+
550
+ Vec<3> tau = ep-sp;
551
+ Vec<3> tau_num = 1.0/num * tau;
552
+ for (int i = 0; i < num; i++)
553
+ {
554
+ Vec<3> x = sp+(i+0.5)*tau_num;
555
+
556
+ if (double rho = L2Norm(p-x); rho > 0)
557
+ {
558
+ Vec<3> drhodp = 1.0/rho * (p-x);
559
+ Complex dGdrho = (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
560
+ (Complex(0, mp.Kappa())/rho - 1.0/sqr(rho));
561
+
562
+ if constexpr (std::is_same<entry_type, Vec<3,Complex>>())
563
+ sum += j*dGdrho * Cross(drhodp, tau_num);
564
+ }
565
+ }
566
+ }
567
+
568
+ return sum;
569
+ }
570
+
571
+ entry_type EvaluateDeriv(Vec<3> p, Vec<3> d) const
572
+ {
573
+ entry_type sum = 0;
574
+ if (childs[0])
575
+ {
576
+ for (auto & child : childs)
577
+ sum += child->EvaluateDeriv(p, d);
578
+ return sum;
579
+ }
580
+
581
+ if (dipoles.Size())
582
+ throw Exception("EvaluateDeriv not implemented for dipoles in SingularMLMultiPole");
583
+
584
+ for (auto [x,c] : charges)
585
+ if (double rho = L2Norm(p-x); rho > 0)
586
+ {
587
+ Vec<3> drhodp = 1.0/rho * (p-x);
588
+ Complex dGdrho = (1/(4*M_PI))*exp(Complex(0,rho*mp.Kappa())) *
589
+ (Complex(0, mp.Kappa())/rho - 1.0/sqr(rho));
590
+ sum += dGdrho * InnerProduct(drhodp, d) * c;
591
+ }
485
592
  return sum;
486
593
  }
487
594
 
@@ -516,9 +623,9 @@ namespace ngfem
516
623
  }
517
624
  else
518
625
  {
519
- if (charges.Size()+dipoles.Size() == 0)
626
+ if (charges.Size()+dipoles.Size()+currents.Size() == 0)
520
627
  {
521
- mp = MultiPole<MPSingular> (-1, mp.Kappa());
628
+ mp = MultiPole<MPSingular,entry_type> (-1, mp.Kappa());
522
629
  return;
523
630
  }
524
631
 
@@ -527,10 +634,13 @@ namespace ngfem
527
634
 
528
635
  for (auto [x,d,c] : dipoles)
529
636
  mp.AddDipole (x-center, d, c);
637
+
638
+ for (auto [sp,ep,j,num] : currents)
639
+ mp.AddCurrent (sp-center, ep-center, j, num);
530
640
  }
531
641
  }
532
642
 
533
- Complex EvaluateMP(Vec<3> p) const
643
+ entry_type EvaluateMP(Vec<3> p) const
534
644
  {
535
645
  if (charges.Size() || dipoles.Size())
536
646
  return Evaluate(p);
@@ -541,22 +651,43 @@ namespace ngfem
541
651
  if (!childs[0]) // || level==1)
542
652
  return Evaluate(p);
543
653
 
544
- Complex sum = 0.0;
654
+ entry_type sum{0.0};
545
655
  for (auto & child : childs)
546
656
  sum += child->EvaluateMP(p);
547
657
  return sum;
548
658
  }
549
-
550
-
551
- void Print (ostream & ost) const
659
+
660
+ entry_type EvaluateMPDeriv(Vec<3> p, Vec<3> d) const
552
661
  {
553
- ost << "c = " << center << ", r = " << r << endl;
662
+ // cout << "EvaluateMPDeriv Singular, p = " << p << ", d = " << d << ", r = " << r << ", center = " << center << endl;
663
+ // cout << "Norm: " << L2Norm(p-center) << " > " << 3*r << endl;
664
+ // cout << "charges.Size() = " << charges.Size() << ", dipoles.Size() = " << dipoles.Size() << endl;
665
+ if (charges.Size() || dipoles.Size() || !childs[0])
666
+ return EvaluateDeriv(p, d);
667
+
668
+ if (L2Norm(p-center) > 3*r)
669
+ return mp.EvalDirectionalDerivative(p-center, d);
670
+
671
+ entry_type sum{0.0};
672
+ for (auto & child : childs)
673
+ sum += child->EvaluateMPDeriv(p, d);
674
+ return sum;
675
+ }
676
+
677
+ void Print (ostream & ost, size_t childnr = -1) const
678
+ {
679
+ if (childnr == -1)
680
+ ost << "c = " << center << ", r = " << r << ", level = " << level << endl;
681
+ else
682
+ ost << "c = " << center << ", r = " << r << ", level = " << level << ", childnr = " << childnr << endl;
554
683
  // for (int i = 0; i < loc_pnts.Size(); i++)
555
684
  for (auto [x,c] : charges)
556
685
  ost << "xi = " << x << ", ci = " << c << endl;
686
+ for (auto [x,d,c] : dipoles)
687
+ ost << "xi = " << x << ", di = " << d << ", ci = " << c << endl;
557
688
 
558
689
  for (int i = 0; i < 8; i++)
559
- if (childs[i]) childs[i] -> Print (ost);
690
+ if (childs[i]) childs[i] -> Print (ost, i);
560
691
  }
561
692
 
562
693
  double Norm () const
@@ -601,6 +732,31 @@ namespace ngfem
601
732
  root.AddDipole(x, d, c);
602
733
  }
603
734
 
735
+ void AddCurrent (Vec<3> sp, Vec<3> ep, Complex j, int num)
736
+ {
737
+ if constexpr (!std::is_same<entry_type, Vec<3,Complex>>())
738
+ throw Exception("AddCurrent needs a singular vectorial MP");
739
+
740
+ root.AddCurrent (sp, ep, j, num);
741
+ /*
742
+ // for testing
743
+ Vec<3> tau = ep-sp;
744
+ Vec<3> tau_num = 1.0/num * tau;
745
+ for (int i = 0; i < num; i++)
746
+ {
747
+ for (int k = 0; k < 3; k++)
748
+ {
749
+ Vec<3> ek{0.0}; ek(k) = 1;
750
+ Vec<3> cp = Cross(tau, ek);
751
+ Vec<3,Complex> source{0.0};
752
+ source(k) = j/double(num);
753
+ if constexpr (std::is_same<entry_type, Vec<3,Complex>>())
754
+ root.AddDipole (sp+(i+0.5)*tau_num, cp, source);
755
+ }
756
+ }
757
+ */
758
+ }
759
+
604
760
  void Print (ostream & ost) const
605
761
  {
606
762
  root.Print(ost);
@@ -634,7 +790,7 @@ namespace ngfem
634
790
  havemp = true;
635
791
  }
636
792
 
637
- Complex Evaluate (Vec<3> p) const
793
+ entry_type Evaluate (Vec<3> p) const
638
794
  {
639
795
  if (havemp)
640
796
  return root.EvaluateMP(p);
@@ -642,17 +798,20 @@ namespace ngfem
642
798
  return root.Evaluate(p);
643
799
  }
644
800
 
801
+ template <typename entry_type2>
645
802
  friend class RegularMLMultiPole;
646
803
  };
647
804
 
648
805
 
649
- inline ostream & operator<< (ostream & ost, const SingularMLMultiPole & mlmp)
806
+ template <typename entry_type>
807
+ inline ostream & operator<< (ostream & ost, const SingularMLMultiPole<entry_type> & mlmp)
650
808
  {
651
809
  mlmp.Print(ost);
652
810
  return ost;
653
811
  }
654
812
 
655
813
 
814
+ template <typename elem_type=Complex>
656
815
  class NGS_DLL_HEADER RegularMLMultiPole
657
816
  {
658
817
  static Array<size_t> nodes_on_level;
@@ -663,11 +822,11 @@ namespace ngfem
663
822
  double r;
664
823
  int level;
665
824
  std::array<unique_ptr<Node>,8> childs;
666
- MultiPole<MPRegular> mp;
825
+ MultiPole<MPRegular,elem_type> mp;
667
826
  Array<Vec<3>> targets;
668
827
  int total_targets;
669
828
 
670
- Array<const SingularMLMultiPole::Node*> singnodes;
829
+ Array<const typename SingularMLMultiPole<elem_type>::Node*> singnodes;
671
830
 
672
831
  Node (Vec<3> acenter, double ar, int alevel, int order, double kappa)
673
832
  : center(acenter), r(ar), level(alevel), mp(MPOrder(ar*kappa), kappa, 1.0/min(1.0, 0.25*r*kappa))
@@ -692,7 +851,7 @@ namespace ngfem
692
851
  }
693
852
  }
694
853
 
695
- void AddSingularNode (const SingularMLMultiPole::Node & singnode, bool allow_refine)
854
+ void AddSingularNode (const typename SingularMLMultiPole<elem_type>::Node & singnode, bool allow_refine)
696
855
  {
697
856
  if (mp.SH().Order() < 0) return;
698
857
  if (singnode.mp.SH().Order() < 0) return;
@@ -781,15 +940,15 @@ namespace ngfem
781
940
  mp.TransformAdd (ch->mp, ch->center-center);
782
941
  ch->LocalizeExpansion(allow_refine);
783
942
  }
784
- mp = MultiPole<MPRegular>(-1, mp.Kappa());
943
+ mp = MultiPole<MPRegular,elem_type>(-1, mp.Kappa());
785
944
  //mp.SH().Coefs()=0.0;
786
945
  }
787
946
  }
788
947
 
789
- Complex Evaluate (Vec<3> p) const
948
+ elem_type Evaluate (Vec<3> p) const
790
949
  {
791
950
  // *testout << "eval p = " << p << ", level = " << level << ", center = " << center << ", r = " << r << endl;
792
- Complex sum = 0.0;
951
+ elem_type sum{0.0};
793
952
  /*
794
953
  if (childs[0])
795
954
  {
@@ -817,6 +976,28 @@ namespace ngfem
817
976
  return sum;
818
977
  }
819
978
 
979
+ elem_type EvaluateDirectionalDerivative (Vec<3> p, Vec<3> d) const
980
+ {
981
+ elem_type sum{0.0};
982
+ // cout << "EvaluateDirectionalDerivative RegularMLMP, r = " << r << ", level = " << level << ", center = " << center << endl;
983
+ // cout << "Singnodes: " << singnodes.Size() << ", childs: " << childs[0] << endl;
984
+
985
+ int childnum = 0;
986
+ if (p(0) > center(0)) childnum += 1;
987
+ if (p(1) > center(1)) childnum += 2;
988
+ if (p(2) > center(2)) childnum += 4;
989
+ if (childs[childnum])
990
+ sum = childs[childnum]->EvaluateDirectionalDerivative(p, d);
991
+ else
992
+ sum = mp.EvalDirectionalDerivative(p-center, d);
993
+
994
+ static Timer t("mptool direct evaluate deriv"); RegionTimer r(t);
995
+ for (auto sn : singnodes)
996
+ sum += sn->EvaluateMPDeriv(p, d);
997
+
998
+ return sum;
999
+ }
1000
+
820
1001
  double Norm() const
821
1002
  {
822
1003
  double norm = L2Norm(mp.SH().Coefs());
@@ -886,13 +1067,27 @@ namespace ngfem
886
1067
  mp = MultiPole<MPRegular>(-1, mp.Kappa());
887
1068
  }
888
1069
 
1070
+
1071
+ void Print (ostream & ost, size_t childnr = -1) const
1072
+ {
1073
+ if (childnr == -1)
1074
+ ost << "c = " << center << ", r = " << r << ", level = " << level << endl;
1075
+ else
1076
+ ost << "c = " << center << ", r = " << r << ", level = " << level << ", childnr = " << childnr << endl;
1077
+ for (auto x : targets)
1078
+ ost << "xi = " << x << endl;
1079
+
1080
+ for (int i = 0; i < 8; i++)
1081
+ if (childs[i]) childs[i] -> Print (ost, i);
1082
+ }
1083
+
889
1084
  };
890
1085
 
891
1086
  Node root;
892
- shared_ptr<SingularMLMultiPole> singmp;
1087
+ shared_ptr<SingularMLMultiPole<elem_type>> singmp;
893
1088
 
894
1089
  public:
895
- RegularMLMultiPole (shared_ptr<SingularMLMultiPole> asingmp, Vec<3> center, double r, int order)
1090
+ RegularMLMultiPole (shared_ptr<SingularMLMultiPole<elem_type>> asingmp, Vec<3> center, double r, int order)
896
1091
  : root(center, r, 0, order, asingmp->Kappa()), singmp(asingmp)
897
1092
  {
898
1093
  if (!singmp->havemp) throw Exception("first call Calc for singular MP");
@@ -934,7 +1129,7 @@ namespace ngfem
934
1129
  root.AddTarget (t);
935
1130
  }
936
1131
 
937
- void CalcMP(shared_ptr<SingularMLMultiPole> asingmp)
1132
+ void CalcMP(shared_ptr<SingularMLMultiPole<elem_type>> asingmp)
938
1133
  {
939
1134
  singmp = asingmp;
940
1135
 
@@ -955,6 +1150,11 @@ namespace ngfem
955
1150
  root.LocalizeExpansion(false);
956
1151
  }
957
1152
 
1153
+ void Print (ostream & ost) const
1154
+ {
1155
+ root.Print(ost);
1156
+ }
1157
+
958
1158
  double Norm() const
959
1159
  {
960
1160
  return root.Norm();
@@ -965,21 +1165,26 @@ namespace ngfem
965
1165
  return root.NumCoefficients();
966
1166
  }
967
1167
 
968
- Complex Evaluate (Vec<3> p) const
1168
+ elem_type Evaluate (Vec<3> p) const
969
1169
  {
970
1170
  // static Timer t("mptool Eval MLMP regular"); RegionTimer r(t);
971
- if (L2Norm(p-root.center) > root.r) return 0.0;
1171
+ if (L2Norm(p-root.center) > root.r) return elem_type{0.0};
972
1172
  return root.Evaluate(p);
973
1173
  }
974
1174
 
975
-
1175
+ elem_type EvaluateDirectionalDerivative (Vec<3> p, Vec<3> d) const
1176
+ {
1177
+ if (L2Norm(p-root.center) > root.r) return elem_type{0.0};
1178
+ return root.EvaluateDirectionalDerivative(p, d);
1179
+ }
1180
+
976
1181
  };
977
-
978
1182
 
979
- inline ostream & operator<< (ostream & ost, const RegularMLMultiPole & mlmp)
1183
+ template <typename elem_type>
1184
+ inline ostream & operator<< (ostream & ost, const RegularMLMultiPole<elem_type> & mlmp)
980
1185
  {
981
- // mlmp.Print(ost);
982
- ost << "RegularMLMultiPole" << endl;
1186
+ mlmp.Print(ost);
1187
+ // ost << "RegularMLMultiPole" << endl;
983
1188
  return ost;
984
1189
  }
985
1190
 
@@ -993,7 +1198,7 @@ namespace ngfem
993
1198
 
994
1199
  class SphericalHarmonicsCF : public CoefficientFunction
995
1200
  {
996
- SphericalHarmonics sh;
1201
+ SphericalHarmonics<Complex> sh;
997
1202
  public:
998
1203
  SphericalHarmonicsCF (int order)
999
1204
  : CoefficientFunction(1, true), sh(order) { }
@@ -1021,16 +1226,16 @@ namespace ngfem
1021
1226
 
1022
1227
 
1023
1228
 
1024
- template <typename RADIAL>
1229
+ template <typename RADIAL, typename entry_type=Complex>
1025
1230
  class MultiPoleCF : public CoefficientFunction
1026
1231
  {
1027
- MultiPole<RADIAL> mp;
1232
+ MultiPole<RADIAL, entry_type> mp;
1028
1233
  Vec<3> center;
1029
1234
  public:
1030
1235
  MultiPoleCF (int order, double kappa, Vec<3> acenter, double scale = 1)
1031
- : CoefficientFunction(1, true), mp(order, kappa, scale), center(acenter) { }
1236
+ : CoefficientFunction(sizeof(entry_type)/sizeof(Complex), true), mp(order, kappa, scale), center(acenter) { }
1032
1237
 
1033
- Complex & Coef(int n, int m) { return mp.Coef(n,m); }
1238
+ entry_type & Coef(int n, int m) { return mp.Coef(n,m); }
1034
1239
  auto & SH() { return mp.SH(); }
1035
1240
  auto & MP() { return mp; }
1036
1241
  Vec<3> Center() const { return center; }
@@ -1040,56 +1245,72 @@ namespace ngfem
1040
1245
 
1041
1246
  virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
1042
1247
  {
1043
- values(0) = mp.Eval(mip.GetPoint()-center);
1248
+ if constexpr (std::is_same<entry_type, Complex>())
1249
+ values(0) = mp.Eval(mip.GetPoint()-center);
1250
+ else
1251
+ values = mp.Eval(mip.GetPoint()-center);
1044
1252
  }
1045
1253
 
1046
1254
  template <typename TARGET>
1047
- void ShiftZ (double z, MultiPole<TARGET> & target) { mp.ShiftZ(z, target); }
1255
+ void ShiftZ (double z, MultiPole<TARGET, entry_type> & target) { mp.ShiftZ(z, target); }
1048
1256
 
1049
1257
  using CoefficientFunction::Transform;
1050
1258
  template <typename TARGET>
1051
- void Transform (MultiPoleCF<TARGET> & target)
1259
+ void Transform (MultiPoleCF<TARGET, entry_type> & target)
1052
1260
  {
1053
1261
  mp.Transform (target.MP(), target.Center()-center);
1054
1262
  }
1055
1263
  };
1056
1264
 
1057
-
1265
+ template <typename entry_type>
1058
1266
  class SingularMLMultiPoleCF : public CoefficientFunction
1059
1267
  {
1060
- shared_ptr<SingularMLMultiPole> mlmp;
1268
+ shared_ptr<SingularMLMultiPole<entry_type>> mlmp;
1061
1269
  public:
1062
1270
  SingularMLMultiPoleCF (Vec<3> center, double r, int order, double kappa)
1063
- : CoefficientFunction(1, true), mlmp{make_shared<SingularMLMultiPole>(center, r, order, kappa)} { }
1271
+ : CoefficientFunction(sizeof(entry_type)/sizeof(Complex), true), mlmp{make_shared<SingularMLMultiPole<entry_type>>(center, r, order, kappa)} { }
1064
1272
 
1065
1273
  virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
1066
1274
  { throw Exception("real eval not available"); }
1067
1275
 
1068
1276
  virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
1069
1277
  {
1070
- values(0) = mlmp->Evaluate(mip.GetPoint());
1278
+ // values(0) = mlmp->Evaluate(mip.GetPoint());
1279
+
1280
+ if constexpr (std::is_same<entry_type, Complex>())
1281
+ values(0) = mlmp->Evaluate(mip.GetPoint());
1282
+ else
1283
+ values = mlmp->Evaluate(mip.GetPoint());
1284
+
1285
+
1071
1286
  }
1072
1287
 
1073
- shared_ptr<SingularMLMultiPole> MLMP() { return mlmp; }
1288
+ shared_ptr<SingularMLMultiPole<entry_type>> MLMP() { return mlmp; }
1074
1289
  };
1075
1290
 
1076
1291
 
1292
+ template <typename entry_type>
1077
1293
  class RegularMLMultiPoleCF : public CoefficientFunction
1078
1294
  {
1079
- shared_ptr<RegularMLMultiPole> mlmp;
1295
+ shared_ptr<RegularMLMultiPole<entry_type>> mlmp;
1080
1296
  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)} { }
1297
+ RegularMLMultiPoleCF (shared_ptr<SingularMLMultiPoleCF<entry_type>> asingmp, Vec<3> center, double r, int order)
1298
+ : CoefficientFunction(sizeof(entry_type)/sizeof(Complex), true), mlmp{make_shared<RegularMLMultiPole<entry_type>>(asingmp->MLMP(), center, r, order)} { }
1083
1299
 
1084
1300
  virtual double Evaluate (const BaseMappedIntegrationPoint & ip) const override
1085
1301
  { throw Exception("real eval not available"); }
1086
1302
 
1087
1303
  virtual void Evaluate (const BaseMappedIntegrationPoint & mip, FlatVector<Complex> values) const override
1088
1304
  {
1089
- values(0) = mlmp->Evaluate(mip.GetPoint());
1305
+ // values(0) = mlmp->Evaluate(mip.GetPoint());
1306
+
1307
+ if constexpr (std::is_same<entry_type, Complex>())
1308
+ values(0) = mlmp->Evaluate(mip.GetPoint());
1309
+ else
1310
+ values = mlmp->Evaluate(mip.GetPoint());
1090
1311
  }
1091
1312
 
1092
- shared_ptr<RegularMLMultiPole> MLMP() { return mlmp; }
1313
+ shared_ptr<RegularMLMultiPole<entry_type>> MLMP() { return mlmp; }
1093
1314
  };
1094
1315
 
1095
1316