MPI Example
This is an MPI example, rewriting the same example in Two Gratings Near-field
s = SimulationGrating.new(); s:SetLattice(1e-6); s:AddMaterial("Au", "fullGold.txt"); s:AddMaterial("Vacuum", "fullVacuum.txt"); s:AddLayer("BottomAir", 0, "Vacuum"); s:AddLayer("GoldSubstrateBottom", 0.5e-6, "Au"); s:AddLayer("GoldGratingBottom", 5e-6,"Au"); s:SetLayerPatternGrating("GoldGratingBottom", "Vacuum", 0.5e-6, 0.2e-6); s:AddLayer("VacGap", 1e-6, "Vacuum"); s:AddLayerCopy("GoldGratingTop", "GoldGratingBottom"); s:AddLayerCopy("GoldSubstrateTop", "GoldSubstrateBottom"); s:AddLayerCopy("TopAir", "BottomAir"); s:SetSourceLayer("GoldSubstrateBottom"); s:SetSourceLayer("GoldGratingBottom"); s:SetProbeLayer("VacGap"); s:OptPrintIntermediate(); s:SetNumOfG(101); s:SetKxIntegralSym(500); s:SetKyIntegralSym(200, 5); s:InitSimulation();
The above are the same as the standard Lua script. The following code configures the MPI.
---------------------------------------------------------------- -- this part is for MPI -- in principle there is no need to change this part for your simulation ---------------------------------------------------------------- -- start MPI local sizeb = buffer.new_buffer(buffer.sizeof(buffer.int)) local rankb = buffer.new_buffer(buffer.sizeof(buffer.int)) MPI.Init() MPI.Comm_rank(MPI.COMM_WORLD, rankb) MPI.Comm_size(MPI.COMM_WORLD, sizeb) local size = buffer.get_typed(sizeb, buffer.int, 0) local rank = buffer.get_typed(rankb, buffer.int, 0) if rank == 0 then s:OutputSysInfo(); end status = MPI.Status() numOfOmega = s:GetNumOfOmega() omega = s:GetOmega(); -- rank 0 is the master node if rank == 0 then s:IntegrateKxKyMPI(rank, size); phi_master = s:GetPhi(); -- master collects values from slave for i = 1,size - 1 do local phi_local = buffer.new_buffer(numOfOmega * buffer.sizeof(buffer.double)); MPI.Recv(phi_local, numOfOmega, MPI.DOUBLE, i, 0, MPI.COMM_WORLD, status); for j = 1, numOfOmega do phi_master[j] = phi_master[j] + buffer.get_typed(phi_local, buffer.double, j - 1); end end -- output all the phi values from the master for i = 1,numOfOmega do print(string.format("%e", omega[i]).."\t"..string.format("%e", phi_master[i])); end -- rank 1-size are the slave nodes else s:IntegrateKxKyMPI(rank, size); local phi_slave = s:GetPhi(); -- slave nodes send phi values back to master local phi_ = buffer.new_buffer(numOfOmega * buffer.sizeof(buffer.double)); for i = 1, numOfOmega do buffer.set_typed(phi_, buffer.double, i - 1, phi_slave[i]); end MPI.Send(phi_, numOfOmega, MPI.DOUBLE, 0, 0, MPI.COMM_WORLD); end MPI.Finalize();
The above code uses master-slave manner, where rank is the master node that collects all the from the other slave nodes, and then sum them together. The code can be run by:
mpirun -np 40 meshMPI main.lua
The corresponding Python MPI version is
from MESH import SimulationGrating s = SimulationGrating() s.SetLattice(1e-6) s.AddMaterial("Au", "fullGold.txt") s.AddMaterial("Vacuum", "fullVacuum.txt") s.AddLayer("BottomAir", 0, "Vacuum") s.AddLayer("GoldSubstrateBottom", 0.5e-6, "Au") s.AddLayer("GoldGratingBottom", 5e-6,"Au") s.SetLayerPatternGrating("GoldGratingBottom", "Vacuum", 0.5e-6, 0.2e-6) s.AddLayer("VacGap", 1e-6, "Vacuum") s.AddLayerCopy("GoldGratingTop", "GoldGratingBottom") s.AddLayerCopy("GoldSubstrateTop", "GoldSubstrateBottom") s.AddLayerCopy("TopAir", "BottomAir") s.SetSourceLayer("GoldSubstrateBottom") s.SetSourceLayer("GoldGratingBottom") s.SetProbeLayer("VacGap") s.OptPrintIntermediate() s.SetNumOfG(50) s.SetKxIntegralSym(2) s.SetKyIntegralSym(2, 5) s.InitSimulation() """ -- this part is for MPI -- in principle there is no need to change this part for your simulation """ from mpi4py import MPI comm = MPI.COMM_WORLD size = comm.Get_size() rank = comm.Get_rank() if rank == 0: s.OutputSysInfo() numOfOmega = s.GetNumOfOmega() if rank == 0: s.IntegrateKxKyMPI(rank, size); phi_master = s.GetPhi() phi = list(phi_master) for i in range(1, size): phi_slave = comm.recv(source = i, tag = 11) for j in range(numOfOmega): phi[j] = phi[j] + phi_slave[j] for i in range(numOfOmega): print phi[i] else: s.IntegrateKxKyMPI(rank, size) phi_slave = s.GetPhi() comm.send(phi_slave, dest = 0, tag = 11)
The code can be run by:
mpirun -np 40 Python main.py