4
$\begingroup$

I am generating a 3D band structure from a slab Hamiltonian and color-coding each eigenvalue by its IPR (defined from the corresponding eignvector, e.g., inverse participation ratio). The numerical diagonalization and IPR calculation are fast, but ListPointPlot3D becomes extremely slow and almost unresponsive when the number of k-points increases.

A minimal version of my code is below.

  1. Define the matrix:
hamSlabXZ[{kx_, kz_}, t3_] := 
 Module[{ny = 5, H0, HL, HR, h00, h01, h10, hL00, hL01, hR00, hR10, 
   HfullCell},
  h00 = ( {
     {0, ta, ta},
     {ta, 0, ta},
     {ta, ta, 0}
    } );
  h01 = ( {
     {0, 0, 0},
     {tz, 0, 0},
     {tb, tz, 0}
    } ); h10 = ( {
     {0, tz, tb},
     {0, 0, tz},
     {0, 0, 0}
    } );
  H0 = KroneckerProduct[IdentityMatrix[ny], h00]
    + KroneckerProduct[DiagonalMatrix[Array[1 &, ny - 1], 1], h01]
    + KroneckerProduct[DiagonalMatrix[Array[1 &, ny - 1], -1], h10];
  hL00 = ( {
      {0, tb, tz},
      {0, 0, 0},
      {0, tz, 0}
     } )*Exp[-I*kx];
  hL01 = ( {
      {0, tz, 0},
      {0, 0, 0},
      {tz, tb, 0}
     } )*Exp[-I*kx];
  HL = KroneckerProduct[IdentityMatrix[ny], hL00]
    + KroneckerProduct[DiagonalMatrix[Array[1 &, ny - 1], 1], hL01];
  hR00 = ( {
      {0, 0, 0},
      {tb, 0, tz},
      {tz, 0, 0}
     } )*Exp[I*kx];
  hR10 = ( {
      {0, 0, tz},
      {tz, 0, tb},
      {0, 0, 0}
     } )*Exp[I*kx];
  HR = KroneckerProduct[IdentityMatrix[ny], hR00]
    + KroneckerProduct[DiagonalMatrix[Array[1 &, ny - 1], -1], hR10];
  HfullCell = H0 + HL + HR;
  
  HfullCell /. {ta -> -1, tb -> -2.5, tz -> 2*t3*Cos[kz]}
  ]
  1. Get the eigenvalues in (kx,kz) plane, together with the corresponding IPR by specifying Style, and storing them with data2DAll
surfband2D[kx_, kz_] := 
 Module[{ham, evals, evecs, ord, evalsSort, evecsSort, iprList, 
   iprNormal, colorlist},
  ham = N@hamSlabXZ[{kx, kz}, -0.02];
  {evals, evecs} = Eigensystem[ham];
  ord = Ordering[evals];
  evalsSort = evals[[ord]];
  evecsSort = evecs[[ord]];
  iprList = Map[Total[(Abs[#]^4)] &, evecsSort];
  iprNormal = iprList/Max[iprList];
  colorlist = 
   Map[Blend[{Lighter[Blue, 2/3], Lighter[Gray, 1/3], Orange, 
       Red}, #] &, iprNormal
    ];
  MapThread[Style, {evalsSort, colorlist}]
  ]
data2DAll = 
  ParallelTable[
   surfband2D[kkx, kkz], {kkx, -\[Pi], \[Pi], 
    0.05 \[Pi]}, {kkz, -\[Pi], \[Pi], 0.05 \[Pi]}];
  1. ListPointPlot it:
ListPointPlot3D[Transpose[data2DAll[[All, All, All]], {3, 2, 1}], 
 AxesLabel -> {kx, kz, Ene}, 
 BoxRatios -> {1, 1, 1.5}]

The result may look like the picture blow, but is getting significantly slow with the increase of (kx,kz) mesh grids. Exampling result

Questions

  1. Is the use of per-point Style inside ListPointPlot3D the main cause of the slowdown?

  2. What is the recommended way to efficiently color a large number of 3D points by an additional scalar quantity (such as IPR)?

  3. A similar issue is found in here, where the top answer adopts a solution by replacing ListPlot with Graphics, just like the answer made by @Craig Carter below this question. So, a further question arises: Is that possible to plot the entire surface via ListPlot3D rather than play with point-dots?

Any insight into the internal rendering behavior of ListPointPlot3D or suggested alternative approaches would be appreciated.

New contributor
liu han is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
$\endgroup$

1 Answer 1

6
$\begingroup$

Skipping ListPlot and creating a 3D graphic directly is pretty fast.

Modify your function to produce 15 {color,Point[{kx,kz,val}]} for a kx,kz:

surfband2DPoints[kx_, kz_] := 
 Module[{ham, evals, evecs, ord, evalsSort, evecsSort, iprList, 
   iprNormal, colorlist}, ham = N@hamSlabXZ[{kx, kz}, -0.02];
  {evals, evecs} = Eigensystem[ham];
  ord = Ordering[evals];
  evalsSort = evals[[ord]];
  evecsSort = evecs[[ord]];
  iprList = Map[Total[(Abs[#]^4)] &, evecsSort];
  iprNormal = iprList/Max[iprList];
  colorlist = 
   Map[Blend[{Lighter[Blue, 2/3], Lighter[Gray, 1/3], Orange, 
       Red}, #] &, iprNormal];
  {colorlist, evalsSort};
  MapThread[{#1, Point[{kx, kz, #2}]} &, {colorlist, evalsSort}]
  ] 

Collect data as before:

data2DAll = 
  ParallelTable[
   surfband2DPoints[kkx, kkz], {kkx, -\[Pi], \[Pi], 
    0.05 \[Pi]}, {kkz, -\[Pi], \[Pi], 0.05 \[Pi]}];

Use the points to construct a Graphics3D object:

Graphics3D[Flatten[data2DAll, 2]]

enter image description here

$\endgroup$
2
  • $\begingroup$ Thank you for the impressive solution. It seems that the rendering procedures of Graphics3D and ListPlot are drastically different. $\endgroup$ Commented yesterday
  • 1
    $\begingroup$ I suspect the slowness is due to the use of Style[..,..]. In your case, I recommend experimenting with using the {kx,kz,e} and using ListPlot3D , or use Interpolation together with Plot3D to plot continuous bands. $\endgroup$ Commented 19 hours ago

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.