5
$\begingroup$

After using MM V12 for a long time on a MacBook Pro 2011, which just lost 8GB or RAM from 16GB, I am trying V14 on a MacMini M2pro with 32GB. I had previously coded a coupled 3D EM problem involving a rectangular wire loop driven by an AC voltage across a gap. The object being to view the quasi-static electric field (conservative plus non-conservative) in air around it and inside the conductor.

Conductor

There are by admission much more efficient ways to do this, but I wanted to see if with FEM I got similar results to ANSYS Maxwell, which by the way cannot solve E-field and H-Field simultaneously due to the use of decoupled solvers. The coupled problem is notoriously ill-conditioned at low frequencies apparently. Anyway, that is not the problem. I have a code version in which the mesh is ca. 27000 tetrahedral elements created by OpenCascadeLink, and that solves OK in V14 on the M2. What surprised me is that in MM I found in the guides that I was able to apply an excitation on the conductor face that was not on the mesh boundary - cool. The field plots for tetrahedral are smooth, but it does not capture the skin effect in the conductor well. To improve that I also have a graded hexahedron mesh in which I used code from Tim Laska in a number of posts:

How to Improve FEM Solution with NDSolve?

In V14 grading the mesh should be easier due to new added features, but I have not implemented it. The code below ran fine on my old MacBook Pro (Intel) while it had 16GB, but it took a while. If I reduce the mesh from 55000 to 16700 it will run on 8GB with a little swap space still needed. The advantage of the hexahedron mesh is it can start to capture the skin effect better in the conductor.

But on v14 on a new Mac mini it eats through memory like crazy and does not finish. In fact I have access to two M2 mini's. One with 16GB and one with 32GB. On the 16GB machine, when I use the 55000 element mesh (nsd=3, nl=4, nw=15, na=15) after 16secs I thought it had solved, but I was still looking at previously solved result plots. I suspect it just hit a memory limit and stopped the kernel. Once it left the NDSolveValue function all variables appear to be cleared by the software.

On the 32GB machine and just the 16700 element mesh (nsd=2, nl=3, nw=10, na=10) it just rapidly consumes memory, such that even with 32GB it is using swap space and after a minute or so it is clear it has problems so I just quit the Kernel.

So I do not know if it is a problem with the Apple Silicon implementation or V14, and why just hexahedron elements. Like I said a tetrahedral version I have works and the hexahedral version worked on V12 with Apple Intel. The wire loop was implemented with 1/4 symmetry and sits in the xy plane at the bottom/middle of the figure below where all the fine mesh is. The rest is air. Permeability and permittivity are constant everywhere.

Hexahedral Mesh 16700 elements

16700 element Hexahedral Code

3D FEM Rectangular Current Loop
Clear["Global`*"];
Needs["NDSolve`FEM`"];
Needs["OpenCascadeLink`"];

cw = 0.02; (*wire conductor X-section width/height*)
cl = 1.0; (*rectangular coil length,center to center of wire*)
gap = 0.01; (*gap between feed conductors*)
hAir = 6.0*cl; (*height/depth air region*)
Vapplied = 100.0;(* +/- voltage applied to each feed wire end*)
\[Mu]o = 4.0*\[Pi]*10^-7; (*is constant everywhere*)
\[Epsilon]o = 8.854*10^-12;(*is constant everywhere*)
\[Omega] = 2.0*\[Pi]*60000; (*frequency of applied voltage*)
\[Sigma]cu = 5.8*10^7;(*conductivity of wire conductor*)
nsd = 2;  (*number of mesh points to subdivide the skin depth at \
conductor surface by*)
nl = 3; (*number of additional mesh points in half a conductor width \
cw/2*)
nw = 10; (*number of wire divisions along each wire part*) 
na = 10; (*number of mesh points to divide the AirRegion of length \
hAir/2 in*)
ng = 2; (*number of mesh points in the gap*)
fap = 0.01; (*distance to first graded mesh points air region*)
fcf = 5; (*distance to first graded mesh point in conductor region as \
a multiple of skin depths*)
sd = Sqrt[2/(\[Omega]*\[Sigma]cu*\[Mu]o)];
cr = cl/2;
(*draw conductor*)
wire1Shape = 
  Cuboid[{cr + cw/2, gap/2, -cw/2}, {cr - cw/2, cr + cw/2, cw/2}];
wire2Shape = 
  Cuboid[{cr + cw/2, cr - cw/2, -cw/2}, {-cr - cw/2, cr + cw/2, cw/2}];
wire3Shape = 
  Cuboid[{-cr - cw/2, cr + cw/2, -cw/2}, {-cr + cw/2, 0, cw/2}];
wireHalfReg = 
  RegionUnion[Region[wire1Shape], Region[wire2Shape], 
   Region[wire3Shape]];
wireMirrorReg = 
  TransformedRegion[wireHalfReg, RotationTransform[Pi, {1, 0, 0}]];
wireReg = RegionUnion[wireHalfReg, wireMirrorReg]

(*Model just 1/4 of the problem using symmetry. Use these functions \
by Tim Laska - slightly modified*)
rateFunc[x0_, xf_, n_, r_, 
   j_] := (xf - x0)*(r^(j/(-1 + n)) - 1.)/(r - 1.) + x0;
meshGrowth[x0_, xf_, n_, r_] := 
  Table[rateFunc[x0, xf, n, r, j], {j, 0, n - 1}];
findGrowthRate[x0_, xf_, n_, fElm_] := 
  Quiet@Abs@
    FindRoot[rateFunc[x0, xf, n, r, 1] - fElm, {r, 1.1, 100000}, 
      Method -> "Brent"][[1, 2]];
meshGrowthByElm[x0_, xf_, n_, fElm_] := 
  N@Sort@Chop@meshGrowth[x0, xf, n, findGrowthRate[x0, xf, n, fElm]];
meshGrowthByElm0[len_, n_, fElm_] := 
  meshGrowthByElm[0.0, len, n, fElm];
flipSegment[l_] := (#1 - #2) & @@ {First[#], #} &@Reverse[l] + 
   l[[1]];
pointsToMesh[data_] := 
  MeshRegion[Transpose[{data}], 
   Line@Table[{i, i + 1}, {i, Length[data] - 1}]];

(*X mesh points*)
pointsX = {-hAir/2, -cr - cw/2, -cr + cw/2, cr - cw/2, cr + cw/2, 
   hAir/2};
pointsAir1X = 
  meshGrowthByElm[-cr - cw/2, -hAir/2, na, -cr - cw/2 - fap];
pointsSkin1X = Subdivide[-cr - cw/2, -cr - cw/2 + sd, nsd];
pointsCond1X = 
  meshGrowthByElm[-cr - cw/2 + sd, -cr, nl, -cr - cw/2 + fcf*sd];
pointsCond2X = 
  meshGrowthByElm[-cr + cw/2 - sd, -cr, nl, -cr + cw/2 - fcf*sd];
pointsSkin2X = Subdivide[-cr + cw/2 - sd, -cr + cw/2, nsd];
pointsWire1X = Subdivide[-cr + cw/2 + sd, cr - cw/2 - sd, nw];
pointsSkin3X = Subdivide[cr - cw/2, cr - cw/2 + sd, nsd];
pointsCond3X = 
  meshGrowthByElm[cr - cw/2 + sd, cr, nl, cr - cw/2 + fcf*sd];
pointsCond4X = 
  meshGrowthByElm[cr + cw/2 - sd, cr, nl, cr + cw/2 - fcf*sd];
pointsSkin4X = Subdivide[cr + cw/2 - sd, cr + cw/2, nsd];
pointsAir2X = 
  meshGrowthByElm[cr + cw/2, hAir/2, na, cr + cw/2 + fap];
pointsX = 
  Union[pointsX, pointsAir1X, pointsSkin1X, pointsCond1X, 
   pointsCond2X, pointsSkin2X, pointsWire1X, pointsSkin3X, 
   pointsCond3X, pointsCond4X, pointsSkin4X, pointsAir2X];
segX = pointsToMesh[pointsX]

(*Y mesh points*)
pointsY = {0.0, gap/2, gap/2 + cw/2, cr - cw/2, cr + cw/2, hAir/2};
pointsGapY = Subdivide[gap/2, ng];
pointsWireY = Subdivide[gap/2 + cw, cr - cw/2, nw];
pointsSkin3Y = Subdivide[cr - cw/2, cr - cw/2 + sd, nsd];
pointsCond3Y = 
  meshGrowthByElm[cr - cw/2 + sd, cr, nl, cr - cw/2 + fcf*sd];
pointsCond4Y = 
  flipSegment@meshGrowthByElm[cr, cr + cw/2 - sd, nl, cr + fcf*sd];
pointsSkin4Y = Subdivide[cr + cw/2 - sd, cr + cw/2, nsd];
pointsAirY = meshGrowthByElm[cr + cw/2, hAir/2, na, cr + cw/2 + fap];
pointsY = 
  Union[pointsY, pointsGapY, pointsWireY, pointsSkin3Y, pointsSkin3Y, 
   pointsSkin3Y, pointsSkin4Y, pointsAirY];
segY = pointsToMesh[pointsY]


(*Z mesh points*)
pointsZ = {0.0, cw/2, hAir/2};
pointsCondZ = flipSegment@meshGrowthByElm0[cw/2 - sd, nl, fcf*sd];
pointsSkinZ = Subdivide[cw/2 - sd, cw/2, nsd];
pointsAirZ = meshGrowthByElm[cw/2, hAir/2, na, cw/2 + fap];
pointsZ = Union[pointsZ, pointsCondZ , pointsSkinZ, pointsAirZ];
segZ = pointsToMesh[pointsZ]

(*Look at conductor cross section meshing*)
condX = pointsToMesh@
   Union[pointsSkin1X, pointsCond1X, pointsCond2X, pointsSkin2X];
condZ = pointsToMesh@Union[pointsCondZ , pointsSkinZ];
a = RegionProduct[condX, condZ];
HighlightMesh[a, Style[1, Orange]]

(*Look at conductor cross section meshing*)
condY = pointsToMesh@
   Union[pointsSkin3Y, pointsCond3Y, pointsCond4Y, pointsSkin4Y];
condZ = pointsToMesh@Union[pointsCondZ , pointsSkinZ];
a = RegionProduct[condY, condZ];
HighlightMesh[a, Style[1, Orange]]

(*Look at conductor cross section meshing*)
condX = pointsToMesh@
   Union[pointsSkin3X, pointsCond3X, pointsCond4X, pointsSkin4X];
condZ = pointsToMesh@Union[pointsCondZ , pointsSkinZ];
a = RegionProduct[condX, condZ];
HighlightMesh[a, Style[1, Orange]]

(*Make 3D 1/4 Region*)
regTotal = RegionProduct[segX, segY, segZ];
HighlightMesh[regTotal, Style[1, Orange]]

crd = MeshCoordinates[regTotal];
inc = Delete[0] /@ MeshCells[regTotal, 3];
halfWire = 
  Graphics3D[{Orange, {wire1Shape, wire2Shape, wire3Shape}}, 
   Boxed -> False];

mesh = ToElementMesh["Coordinates" -> crd, 
  "MeshElements" -> {HexahedronElement[inc]}]
Show[halfWire, mesh["Wireframe"]]

(*define coil conductive region*)
reg1 = 0 <= z <= cw/2;
reg2 = (cr - cw/2) <= x <= (cr + cw/2) && (gap/2) <= 
    y <= (cr + cw/2);
reg3 = (-cr - cw/2) <= x <= (cr - cw/2) && (cr - cw/2) <= 
    y <= (cr + cw/2);
reg4 = (-cr - cw/2) <= x <= (-cr + cw/2) && 0 <= y <= cr - cw/2;
reg5 = (cr - cw/2) <= x <= (cr + cw/2) && y < gap/2 && 
   reg1; (*gap region has no conductivity*)
\[Sigma] = 
  Piecewise[{{\[Sigma]cu, reg1 && (reg2 || reg3 || reg4) && ! reg5}}, 
   10]; (*conductivity*)

(*define magnetic vector potential*)
mvpA = {mvpAx[x, y, z], mvpAy[x, y, z], mvpAz[x, y, z]};

(*Assign magnetic vector potential on problem boundary, set A x n = 0 \
for to enforce tangential magnetic flux, except on z=0 where flux is \
normal*)
\[CapitalGamma]d1 = {DirichletCondition[mvpAx[x, y, z] == 0, 
    y == 0 || y == hAir/2 || z == hAir/2], 
   DirichletCondition[mvpAy[x, y, z] == 0, 
    x == hAir/2 || x == -hAir/2 || z == hAir/2],
   DirichletCondition[mvpAz[x, y, z] == 0, 
    x == -hAir/2 || x == hAir/2 || y == 0 || y == hAir/2 || z == 0]};

(*Scalar voltage potential on wire ends*)
\[CapitalGamma]d2 = {DirichletCondition[v[x, y, z] == 0, y == 0], 
   DirichletCondition[v[x, y, z] == Vapplied, 
    cr - cw/2 <= x <= cr + cw/2 && y == gap/2 && 
     0 \[LessSlantEqual] z \[LessSlantEqual] cw/2]};

(*define Coulomb gauged pde operators*)
op1 = Laplacian[
    mvpA, {x, y, z}] - \[Mu]o*(\[Sigma] + I*\[Omega]*\[Epsilon]o)*
    Grad[v[x, y, z], {x, y, 
      z}] - \[Mu]o*(I*\[Omega]*\[Sigma] - \[Omega]^2*\[Epsilon]o)*mvpA;
op2 = Div[(\[Sigma] + I*\[Omega]*\[Epsilon]o)*
     Grad[v[x, y, z], {x, y, z}] - I*\[Omega]*\[Sigma]*mvpA, {x, y, 
    z}];

(*Solve*)
soln = {potAx, potAy, potAz, potV} = 
   NDSolveValue[{op1 == {0, 0, 0}, 
     op2 == 0, \[CapitalGamma]d1, \[CapitalGamma]d2}, {mvpAx, mvpAy, 
     mvpAz, v}, {x, y, z} \[Element] mesh, 
    Method -> {"FiniteElement", 
      InterpolationOrder -> {mvpAx -> 1, mvpAy -> 1, mvpAz -> 1, 
        v -> 1}}];
(*Electric Field*)
ex = -D[potV[x, y, z], x] - potAx[x, y, z]*I*\[Omega];
ey = -D[potV[x, y, z], y] - potAy[x, y, z]*I*\[Omega];
ez = -D[potV[x, y, z], z] - potAz[x, y, z]*I*\[Omega];

(*Results*)
Plot[{Re[ex] /. {x -> a, y -> 1, z -> 0}, 
  Re[ey] /. {x -> a, y -> 1, z -> 0}, 
  Re[ez] /. {x -> a, y -> 1, z -> 0}}, {a, -hAir/2, hAir/2}, 
 AxesLabel -> {"x distance (m)", "(V/m)"}, 
 PlotLabel -> "Electric Field along x-dir line at y=1.0m and z=0m ", 
 PlotRange -> Full]

Plot[{Re[ex] /. {x -> -1, y -> a, z -> 0}, 
  Re[ey] /. {x -> -1, y -> a, z -> 0}, 
  Re[ez] /. {x -> -1, y -> a, z -> 0}}, {a, 0, hAir/2}, 
 AxesLabel -> {"y distance (m)", "(V/m)"}, 
 PlotLabel -> "Electric Field along y-dir line at x=-1.0m and z=0m ", 
 PlotRange -> Full]

Plot[Re[potV[x, y, z]] /. {x -> a, y -> 1, z -> 0}, {a, -hAir/2, 
  hAir/2}, AxesLabel -> {"x distance (m)", "(V/m)"}, 
 PlotLabel -> "Scalar Potential along x-dir line at y=1.0m and z=0m ",
  PlotRange -> Full]

I am at a loss, I was planning to upgrade to V14 (computer is already purchased!), but this is a problem for me. Any suggestions to possible reasons and/or work around? I would be interested to hear if others can run the code and on what platform.

Regards

Andrew

$\endgroup$
7
  • $\begingroup$ Please do an experiment and run this example under rosetta. $\endgroup$
    – user21
    Commented Mar 28 at 7:48
  • $\begingroup$ The code runs (produces plots) in a few seconds on a Linux box with Version 14.0. $\endgroup$
    – user21
    Commented Mar 28 at 7:55
  • $\begingroup$ Thanks for the tip. Under Rosetta it does run. For the 16700 Element mesh Absolute Timing and MaxMemoryUsed around NDSolveValue are 23.3secs and 2.65GB. For the 55000 element version 120secs and 12.67GB. $\endgroup$
    – Greenasnz
    Commented Mar 28 at 8:14
  • $\begingroup$ Info: The Tetrahedral (22500 elements, Scalar Potential 2nd order, Vector Potentials 1st Order) version with Rosetta needs 15.37secs and 1.25GB, and without Rosetta 9.08secs and 5.3GB $\endgroup$
    – Greenasnz
    Commented Mar 28 at 8:20
  • 1
    $\begingroup$ OK I will report it. On a 2011 MacBook Pro 2011 values for the Tet Version are 21.2secs and 1.22GB. For its age the old laptop was pretty good. $\endgroup$
    – Greenasnz
    Commented Mar 28 at 8:35

1 Answer 1

6
$\begingroup$

The problem is that Apple Silicon does not support MKL and thus Pardiso, the LinearSolve method the FEM uses, is not available. For now, the solution is to run under Rosetta.

$\endgroup$
2
  • $\begingroup$ Yes, after reporting it to Wolfram they confirmed that, and said they will add MKL and Pardiso it to the list to make ARM native. $\endgroup$
    – Greenasnz
    Commented Mar 29 at 6:21
  • 1
    $\begingroup$ I found this post useful to create a kernel that starts in "Rosetta Mode" : mathematica.stackexchange.com/questions/282745/… $\endgroup$
    – Greenasnz
    Commented Mar 29 at 7:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.