From c1f9635ad4deb43ad414bd3d772295a573953c2b Mon Sep 17 00:00:00 2001
From: Guillaume Demesy <guillaume.demesy@fresnel.fr>
Date: Fri, 7 May 2021 14:27:20 +0000
Subject: [PATCH] standalone/fast T-matrix computation (no python)

---
 .../scattererTmatrix.pro                      | 267 ++++++++++++++++++
 1 file changed, 267 insertions(+)
 create mode 100644 ElectromagneticScattering/scattererTmatrix.pro

diff --git a/ElectromagneticScattering/scattererTmatrix.pro b/ElectromagneticScattering/scattererTmatrix.pro
new file mode 100644
index 0000000..97da573
--- /dev/null
+++ b/ElectromagneticScattering/scattererTmatrix.pro
@@ -0,0 +1,267 @@
+///////////////////////////////
+// Author : Guillaume Demesy //
+// scattererTmatrix.pro      //
+///////////////////////////////
+
+Include "scattererTmatrix_data.geo";
+myDir = "resT/";
+
+Group {
+  Scat_In        = Region[1];
+  Scat_Out       = Region[2];
+  Domain         = Region[{Scat_In,Scat_Out}];
+  PMLs           = Region[3];
+  All_domains    = Region[{Scat_In,Scat_Out,PMLs}];
+  SurfInt        = Region[{10}];
+  SurfDirichlet  = Region[{20}];
+}
+
+Function{
+  I[]         = Complex[0,1];
+  avoid_sing  = 1.e-14;
+  mu0         = 4*Pi*100.0*nm;
+  epsilon0    = 8.854187817e-3*nm;
+  cel         = 1.0/Sqrt[epsilon0 * mu0];
+  Freq        = cel/lambda0;
+  omega0      = 2.0*Pi*Freq;
+  k_Out       = 2.0*Pi*Sqrt[epsr_Out_re]/lambda0;
+  R3D[]   = Sqrt[X[]^2+Y[]^2+Z[]^2];
+  R2D[]   = Sqrt[X[]^2+Y[]^2];
+  cos_theta[] = Z[]/(R3D[]+avoid_sing);
+  theta[]     = Acos[cos_theta[]];
+  phi[]       = Atan2[-Y[],-X[]]+Pi;
+  cart2sph[]  =   Tensor[X[]/R3D[], Y[]/R3D[], Z[]/R3D[],       
+                         X[]*Z[]/(R3D[]*R2D[]), Y[]*Z[]/(R3D[]*R2D[]), -(X[]^2+Y[]^2)/(R3D[]*R2D[]),
+                        -Y[]/R2D[], X[]/R2D[],0];
+  R[] = Vector[X[]/R3D[], Y[]/R3D[], Z[]/R3D[]];
+
+  a_pml =  1.;
+  b_pml = -siwt;
+
+  sr[]         = Complex[a_pml,b_pml];
+  sphi[]       = Complex[1,0];
+  stheta[]     = Complex[1,0];
+  r_tild[]     = r_pml_in + (R3D[] - r_pml_in) * sr[];
+  theta_tild[] = theta[];
+  pml_tens_temp1[]  = TensorDiag[(r_tild[]/R3D[])^2 * sphi[]*stheta[]/sr[],
+                                 (r_tild[]/R3D[])   * sr[]*stheta[]/sphi[],
+                                 (r_tild[]/R3D[])   * sphi[]*sr[]/stheta[]];
+  pml_tens_temp2[]  = Rotate[pml_tens_temp1[],0,-theta[]-Pi/2,0];
+  pml_tens[]        = Rotate[pml_tens_temp2[],0,0,-phi[]];
+
+  epsilonr_In[]       = Complex[epsr_In_re  , epsr_In_im];
+  epsilonr_Out[]      = Complex[epsr_Out_re , epsr_Out_im];
+
+  epsilonr[Scat_In]   = epsilonr_In[]  * TensorDiag[1.,1.,1.];
+  epsilonr[Scat_Out]  = epsilonr_Out[] * TensorDiag[1.,1.,1.];
+  epsilonr[PMLs]      = pml_tens[];
+                          
+  epsilonr1[Scat_In]  = epsilonr_Out[] * TensorDiag[1.,1.,1.];
+  epsilonr1[Scat_Out] = epsilonr_Out[] * TensorDiag[1.,1.,1.];                
+  epsilonr1[PMLs]     = pml_tens[];
+                          
+  mur[Scat_In]        = TensorDiag[1.,1.,1.];
+  mur[Scat_Out]       = TensorDiag[1.,1.,1.];
+  mur[PMLs]           = pml_tens[];
+
+  For pe In {1:p_max}
+    ne = Floor[Sqrt[pe]];
+    me = ne*(ne+1) - Floor[pe];
+    Mnm_source~{pe}[] = Mnm[1,ne,me,XYZ[],k_Out];
+    Nnm_source~{pe}[] = Nnm[1,ne,me,XYZ[],k_Out];
+    Mnm_out~{pe}[]    = Mnm[3,ne,me,XYZ[],k_Out];
+    Nnm_out~{pe}[]    = Nnm[3,ne,me,XYZ[],k_Out];
+    Xnm~{pe}[]        = Xnm[ne,me,X[],Y[],Z[]];
+    Ynm~{pe}[]        = Ynm[ne,me,X[],Y[],Z[]];
+    Znm~{pe}[]        = Znm[ne,me,X[],Y[],Z[]];
+    Ynm_r~{pe}[]      = Ynm[ne,me,X[],Y[],Z[]] * R[];
+    source_M~{pe}[]   = (omega0/cel)^2*(epsilonr[]-epsilonr1[])*Mnm_source~{pe}[];
+    source_N~{pe}[]   = (omega0/cel)^2*(epsilonr[]-epsilonr1[])*Nnm_source~{pe}[];
+    SphHankelOutgoing_n~{pe}[]   = (JnSph[ne  ,k_Out*r_pml_in]- siwt * I[]*YnSph[ne  ,k_Out*r_pml_in]) ;
+    SphHankelOutgoing_nm1~{pe}[] = (JnSph[ne-1,k_Out*r_pml_in]- siwt * I[]*YnSph[ne-1,k_Out*r_pml_in]) ;
+    dRicattiBessel~{pe}[]        = (k_Out * r_pml_in * (SphHankelOutgoing_nm1~{pe}[]-((ne+1)/((k_Out*r_pml_in))) * SphHankelOutgoing_n~{pe}[]) + SphHankelOutgoing_n~{pe}[]);
+    normalize_fhnm_X~{pe}[]      = 1/SphHankelOutgoing_n~{pe}[];
+    normalize_fenm_Z~{pe}[]      = k_Out*r_pml_in/dRicattiBessel~{pe}[];
+    normalize_fenm_Y~{pe}[]      = k_Out*r_pml_in/(SphHankelOutgoing_n~{pe}[]*Sqrt[ne*(ne+1)]);
+  EndFor  
+}
+
+Constraint {
+  {Name Dirichlet; Type Assign;
+   Case {
+     { Region SurfDirichlet; Value 0.; }
+   }
+  }
+}
+
+Jacobian {
+  { Name JVol ;
+    Case {
+      { Region All ; Jacobian Vol ; }
+    }
+  }
+  { Name JSur ;
+    Case {
+      { Region All ; Jacobian Sur ; }
+    }
+  }
+}
+
+Integration {
+  { Name Int_1 ;
+    Case { 
+      { Type Gauss ;
+        Case { 
+          { GeoElement Point        ; NumberOfPoints   1 ; }
+          { GeoElement Line2        ; NumberOfPoints   4 ; }
+          { GeoElement Triangle     ; NumberOfPoints  12 ; }
+          { GeoElement Triangle2    ; NumberOfPoints  12 ; }
+          { GeoElement Tetrahedron  ; NumberOfPoints  17 ; }
+          { GeoElement Tetrahedron2 ; NumberOfPoints  17 ; }
+        }
+      }
+    }
+  }
+}
+
+FunctionSpace {
+  { Name Hcurl; Type Form1;
+    BasisFunction {
+      { Name sn; NameOfCoef un; Function BF_Edge;
+        Support Region[{All_domains,SurfInt}]; Entity EdgesOf[All]; }
+      { Name sn2; NameOfCoef un2; Function BF_Edge_2E;
+        Support Region[{All_domains,SurfInt}]; Entity EdgesOf[All]; }
+        If (is_FEM_o2==1)
+          { Name sn3; NameOfCoef un3; Function BF_Edge_3F_b;
+            Support Region[{All_domains,SurfInt}]; Entity FacetsOf[All]; }
+          { Name sn4; NameOfCoef un4; Function BF_Edge_3F_c;
+            Support Region[{All_domains,SurfInt}]; Entity FacetsOf[All]; }
+          { Name sn5; NameOfCoef un5; Function BF_Edge_4E;
+            Support Region[{All_domains,SurfInt}]; Entity EdgesOf[All]; }
+         EndIf
+    }
+    Constraint {
+      { NameOfCoef un;  EntityType EdgesOf ; NameOfConstraint Dirichlet; }
+      { NameOfCoef un2; EntityType EdgesOf ; NameOfConstraint Dirichlet; }
+      If (is_FEM_o2==1)
+        { NameOfCoef un3; EntityType FacetsOf ; NameOfConstraint Dirichlet; }
+        { NameOfCoef un4; EntityType FacetsOf ; NameOfConstraint Dirichlet; }  
+        { NameOfCoef un5; EntityType EdgesOf  ; NameOfConstraint Dirichlet; }  
+      EndIf
+    }
+  }
+}
+
+Formulation {
+  {Name VPWMN_helmholtz_vector; Type FemEquation;
+   Quantity {
+     { Name u; Type Local; NameOfSpace Hcurl;}
+    }
+    Equation {
+      Galerkin { [-1/mur[]*Dof{Curl u}             , {Curl u}]; In All_domains; Jacobian JVol; Integration Int_1;  }
+      Galerkin { [(omega0/cel)^2*epsilonr[]*Dof{u} , {u}     ]; In All_domains; Jacobian JVol; Integration Int_1;  }
+      Galerkin { [ (omega0/cel)^2*(epsilonr[]-epsilonr1[])*
+                      ($isN ? Nnm[1,$NE,$ME,XYZ[],k_Out] : Mnm[1,$NE,$ME,XYZ[],k_Out]) 
+                                                    , {u} ]; In Scat_In; Jacobian JVol; Integration Int_1;}      
+    }
+  }
+}
+
+Resolution {
+  { Name res_VPWall_helmholtz_vector;
+    System {
+      { Name T; NameOfFormulation VPWMN_helmholtz_vector; Type ComplexValue; }
+  }
+  Operation {
+    CreateDir[Str[myDir]];        
+    For pe In {1:p_max}
+      Evaluate[ $isN = 0 ];
+      Evaluate[ $PE  = pe ];
+      Evaluate[ $NE  = Floor[Sqrt[$PE]] ];
+      Evaluate[ $ME  = $NE*($NE+1) - Floor[$PE] ];
+      If (pe==1)
+        Generate[T];
+        Solve[T];
+      EndIf
+      GenerateRHS[T];
+      SolveAgain[T];
+      PostOperation[VPWM_postop~{pe}];
+      Evaluate[$isN=1];
+      GenerateRHS[T];
+      SolveAgain[T];
+      PostOperation[VPWN_postop~{pe}];
+    EndFor
+    }
+  }
+}
+
+PostProcessing {
+  For pe In {1:p_max}
+    { Name VPWM_postpro~{pe}; NameOfFormulation VPWMN_helmholtz_vector; NameOfSystem T;
+      Quantity {
+        { Name E_scat           ; Value { Local { [{u}]; In All_domains; Jacobian JVol; } } }
+        { Name H_scat           ; Value { Local { [siwt*I[]/(mur[]*mu0*omega0)*{Curl u}]; In All_domains; Jacobian JVol; } } }
+        { Name Mnm_source~{pe}  ; Value { Local { [   Mnm_source~{pe}[] ]; In All_domains; Jacobian JVol; } } }
+
+        For po In {1:p_max}
+          { Name feM~{pe}~{po} ; Value { Integral { [ (1/r_pml_in)^2 *normalize_fenm_Z~{po}[]*  {u}*Conj[Znm~{po}[]]  ]; In SurfInt; Integration Int_1 ; Jacobian JSur; } } }
+          { Name fhM~{pe}~{po} ; Value { Integral { [ (1/r_pml_in)^2 *normalize_fhnm_X~{po}[]*  {u}*Conj[Xnm~{po}[]]  ]; In SurfInt; Integration Int_1 ; Jacobian JSur; } } }
+        EndFor
+      }
+    }
+    { Name VPWN_postpro~{pe}; NameOfFormulation VPWMN_helmholtz_vector; NameOfSystem T;
+      Quantity {
+        { Name E_scat            ; Value { Local { [{u}]; In All_domains; Jacobian JVol; } } }
+        { Name H_scat            ; Value { Local { [siwt*I[]/(mur[]*mu0*omega0)*{Curl u}]; In All_domains; Jacobian JVol; } } }
+        { Name Nnm_source~{pe}   ; Value {    Local { [   Nnm_source~{pe}[] ]; In All_domains; Jacobian JVol; } } }
+        For po In {1:p_max}
+          { Name feN~{pe}~{po}  ; Value { Integral { [ (1/r_pml_in)^2 *normalize_fenm_Z~{po}[]*  {u}*Conj[Znm~{po}[]]  ]; In SurfInt; Integration Int_1 ; Jacobian JSur; } } }
+          { Name fhN~{pe}~{po}  ; Value { Integral { [ (1/r_pml_in)^2 *normalize_fhnm_X~{po}[]*  {u}*Conj[Xnm~{po}[]]  ]; In SurfInt; Integration Int_1 ; Jacobian JSur; } } }
+        EndFor
+      }
+    }
+  EndFor
+}
+
+PostOperation {
+  For pe In {1:p_max}
+    {Name VPWM_postop~{pe}; NameOfPostProcessing VPWM_postpro~{pe} ;
+      Operation {
+        If (flag_plotcuts==1)
+          Print [ E_scat , OnGrid
+                {(r_pml_in-1*nm)*Sin[$B]*Cos[$C], (r_pml_in-1*nm)*Sin[$B]*Sin[$C], (r_pml_in-1*nm)*Cos[$B]} 
+                {(r_pml_in-1*nm), {sph_scan : Pi-sph_scan+(Pi-2.0*sph_scan)/(10*(npts_plot_theta-1.0)) : (Pi-2.0*sph_scan)/(npts_plot_theta-1.0)}, 
+                {sph_scan : 2.0*Pi-sph_scan+(2.0*Pi-2.0*sph_scan)/(10*(npts_plot_phi-1.0)) : (2.0*Pi-2.0*sph_scan)/(npts_plot_phi-1.0)} }, 
+                File StrCat[myDir,StrCat["E_scat_onsphere_cart_M",Sprintf["%g.pos",pe]]],
+                Name StrCat["E_scat_onsphere_cart_M",Sprintf["%g",pe]]];
+        EndIf
+        For po In {1:p_max}
+          Print[feM~{pe}~{po}[SurfInt] , OnGlobal, Format Table, File StrCat[myDir,StrCat[StrCat["feM_",Sprintf["pe%g",pe]],Sprintf["po%g.dat",po]]]];
+          Print[fhM~{pe}~{po}[SurfInt] , OnGlobal, Format Table, File StrCat[myDir,StrCat[StrCat["fhM_",Sprintf["pe%g",pe]],Sprintf["po%g.dat",po]]]];
+        EndFor
+      }
+    }
+    {Name VPWN_postop~{pe}; NameOfPostProcessing VPWN_postpro~{pe} ;
+      Operation {
+        If (flag_plotcuts==1)
+          Print [ E_scat , OnGrid
+                {(r_pml_in-1*nm)*Sin[$B]*Cos[$C], (r_pml_in-1*nm)*Sin[$B]*Sin[$C], (r_pml_in-1*nm)*Cos[$B]} 
+                {(r_pml_in-1*nm), {sph_scan : Pi-sph_scan+(Pi-2.0*sph_scan)/(10*(npts_plot_theta-1.0)) : (Pi-2.0*sph_scan)/(npts_plot_theta-1.0)}, 
+                {sph_scan : 2.0*Pi-sph_scan+(2.0*Pi-2.0*sph_scan)/(10*(npts_plot_phi-1.0)) : (2.0*Pi-2.0*sph_scan)/(npts_plot_phi-1.0)} }, 
+                File StrCat[myDir,StrCat["E_scat_onsphere_cart_N",Sprintf["%g.pos",pe]]],
+                Name StrCat["E_scat_onsphere_cart_N",Sprintf["%g",pe]]];
+        EndIf
+        For po In {1:p_max}
+          Print[feN~{pe}~{po}[SurfInt] , OnGlobal, Format Table, File StrCat[myDir,StrCat[StrCat["feN_",Sprintf["pe%g",pe]],Sprintf["po%g.dat",po]]]];
+          Print[fhN~{pe}~{po}[SurfInt] , OnGlobal, Format Table, File StrCat[myDir,StrCat[StrCat["fhN_",Sprintf["pe%g",pe]],Sprintf["po%g.dat",po]]]];
+        EndFor      
+      }
+    }
+  EndFor
+}
+
+DefineConstant[
+  R_ = {"res_VPWall_helmholtz_vector", Name "GetDP/1ResolutionChoices", Visible 1},
+  C_ = {"-solve -pos -petsc_prealloc 200 -ksp_type preonly -pc_type lu -pc_factor_mat_solver_type mumps", Name "GetDP/9ComputeCommand", Visible 1},
+  P_ = {"", Name "GetDP/2PostOperationChoices", Visible 0}];
+
-- 
GitLab