Waffle is a C++ 2017 program to solve the stationary wave equation in a two-dimensional disordered medium of arbitrary shape. The name is a contraction of "Wave Field From Finite Elements". This program primarily focuses on the computation of the transmission and reflection matrices between two or more ducts, the distribution of transmission eigenvalues1, and the profile of transmission eigenstates (aka transmission eigenchannels23).
The starting point of all wave simulations is the computation of the retarded modal Green's function
where
where
where
where
The transmission eigenvalue distribution
where
where
where
The intensity profile of transmission eigenstate is therefore given by
where
In the program, the equations above are discretized over a two-dimensional square lattice of step
However, by choosing
This program has been written by David Gaspard (Institut Langevin, ESPCI Paris, PSL University, CNRS) mainly in August 2025. This research has been supported by the ANR project MARS_light under reference ANR-19-CE30-0026, by the program "Investissements d'Avenir" launched by the French Government. It also received support from a grant of the Simons Foundation (No. 1027116).
The source files can be downloaded using the git clone command.
To compile the program, call the make utility in the root directory:
make allThis should generate an executable.
The program requires a C++ compiler, such as from the GNU Compiler Collection, and the libraries OpenBLAS, UMFPACK, MUMPS, and libpng.
It also calls Python 3 with the NumPy, Matplotlib, and csv modules, but also the command pdflatex from TeX Live with the PGFPlots package to process graphical outputs automatically.
The recommended way to launch the program is through the run script:
./runThis script defines the environment variables and calls the executable.
The executable is built from the src/Main.cpp file which contains the computation instructions in C++.
The first step is to define the mesh over which the wave equation will be solved.
This can be done by instantiating a SquareMesh object as follows
SquareMesh mesh("model/image.png");where model/image.png can be replaced by the file path of any image in the model/ folder or elsewhere on the host machine.
This model image completely defines the mesh structure and uses the following color code:
- White (
#FFFFFF): The pixel is void and should be skipped from the mesh. - Black (
#000000): The pixel is added to the mesh. The default boundary condition between black and white pixels are Dirichlet boundary conditions$\psi(\mathbf{r})=0$ . - Red (
#FF0000): Black pixels surrounding a red pixel are flagged as belonging to an input duct for the construction of the transmission matrix. Red pixels are not added to the mesh. - Blue (
#0000FF): Black pixels surrounding a blue pixel are flagged as belonging to an output duct for the construction of the transmission matrix. Blue pixels are not added to the mesh. - Green (
#00FF00): Black pixels surrounding a green pixels are flagged as belonging to a duct which is neither input nor output and thus ignored from the transmission matrix. Green pixels are not added to the mesh.
Note that red (#FF0000), blue (#0000FF), and green (#00FF00) pixels assume free-escape boundary conditions presented before.
It is worth noting that SquareMesh objects can also be generated procedurally using the methods found in the file src/SquareMesh.hpp.
This can be helpful if the boundaries are complicated or change randomly from one simulation to the other.
A WaveSystem object (containing the potential, the discretization of the wave equation, and the Green's function) is then instantiated by the command:
WaveSystem sys(sysname, mesh, kh, density, holscat, holabso);where
sysnameis a string containing the full name of the system, and which will be used for file output.meshis theSquareMeshobject initialized from a model image (see above).khis the product of the wavenumber and the mesh step.densityis the density of pixels which are given a random potential disorder between 0 and 1.holscatis the ratio of the mesh step over the scattering mean free path.holabsois the ratio of the mesh step over the ballistic absorption length.
The WaveSystem object is the main computational object of the program.
Computations can be performed by calling the methods of WaveSystem (see also src/WaveSystem.hpp).
For instance, in order to setup a new random realization of the disorder, one can call
uint64_t seed = 1;
sys.setDisorder(seed);where seed is a long integer uniquely representing the realization of the disorder.
The transmission matrix tmat associated with the propagation from input ducts (red #FF0000 pixels) to output ducts (blue #0000FF pixels) can then be computed using
ComplexMatrix tmat(sys.getNOutputProp(), sys.getNInputProp());
sys.transmissionMatrix(tmat);Frequent tasks have their own methods. For instance, the computation of transmission eigenvalues can be directly achieved with
RealMatrix tval(std::min(sys.getNOutputProp(), sys.getNInputProp()), 1);
sys.addTSpectrum(tval);without having to handle the transmission matrix.
On output, the transmission eigenvalues are stored in the column matrix tval.
Another useful procedure is the following one, which simultaneously compute the transmission eigenvalues and the intensity profile of transmission eigenstates in specific intervals of transmission eigenvalues:
const int nprofile = 3;
const RealMatrix trange(nprofile, 2);
trange(0, 0) = 0.998; trange(0, 1) = 0.002; // Interval is T=[0.996, 1].
trange(1, 0) = 0.500; trange(1, 1) = 0.010; // Interval is T=[0.49, 0.51].
trange(2, 0) = 0.100; trange(2, 1) = 0.005; // Interval is T=[0.095, 0.105].
RealMatrix tprofile(sys.getNPoint(), nprofile):
RealMatrix nsample(nprofile, 1);
RealMatrix tval(std::min(sys.getNOutputProp(), sys.getNInputProp()), 1);
sys.addITransmission(trange, tprofile, nsample, tval);where
trangeis an input matrix with two columns, the first column defined the center of intervals over which the transmission eigenstates are desired, and the second column are the half width of intervals. The number of rows of this matrix determines the number of transmission eigenstates profiles.tprofileis a matrix containing, on output, the intensity profile of transmission eigenstates, one per column. If multiple eigenvalues are found in the same interval, then they are summed up (not averaged). The method adds the profiles directly totprofile, so this matrix must be initialized to zero.nsampleis a column matrix containing, on output, the number of transmission eigenvalues (and thus eigenstates) found in the intervals prescribed bytrange. This matrix must have as many rows astrange, and one column. The method increments the number of found transmission eigenvalues innsample, so this matrix must be initialized to zero.tvalis a column matrix containing, on output, all the transmission eigenvalues (should they belong to the intervals oftrangeor not).
The full list of methods can be found in the header file src/WaveSystem.hpp and in the implementation file src/WaveSystem.cpp.
Footnotes
-
C. W. J. Beenakker, Random-matrix theory of quantum transport, Rev. Mod. Phys. 69, 731 (1997). ↩
-
W. Choi, A. P. Mosk, Q.-H. Park, and W. Choi, Transmission eigenchannels in a disordered medium, Phys. Rev. B 83, 134207 (2011). ↩
-
M. Davy, Z. Shi, J. Park, C. Tian, and A. Z. Genack, Universal structure of transmission eigenchannels inside opaque media, Nat. Commun. 6, 6893 (2015). ↩
-
D. S. Fisher and P. A. Lee, Relation between conductivity and transmission matrix, Phys. Rev. B 23, 6851-6854 (1981). ↩