-
Notifications
You must be signed in to change notification settings - Fork 640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
automatic kpoint guess update #1233
Conversation
This PR seems to be speeding up the import meep as mp
import argparse
def main(args):
resolution = 20 # pixels/unit length (1 um)
h = args.hh
w = args.w
nSi = 3.45
Si = mp.Medium(index=nSi)
nSiO2 = 1.45
SiO2 = mp.Medium(index=nSiO2)
sxy = 4
sz = 4
cell_size = mp.Vector3(sxy,sxy,sz)
# input waveguide
geometry = [mp.Block(material=Si,
center=mp.Vector3(),
size=mp.Vector3(mp.inf,w,h))]
# substrate
geometry.append(mp.Block(material=SiO2,
center=mp.Vector3(),
size=mp.Vector3(mp.inf,mp.inf,0.5*(sz-h))))
dpml = 1.0
boundary_layers = [mp.PML(dpml)]
# mode frequency
fcen = 1/1.55
# source width
df = 0.2*fcen
sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=df),
component=mp.Ey,
size=mp.Vector3(0,sxy-2*dpml,sz-2*dpml),
center=mp.Vector3(-0.5*sxy+dpml),
eig_match_freq=True,
eig_parity=mp.ODD_Y,
eig_kpoint=mp.Vector3(1.5,0,0),
eig_resolution=32)]
symmetries = [mp.Mirror(mp.Y,-1)]
sim = mp.Simulation(resolution=resolution,
cell_size=cell_size,
boundary_layers=boundary_layers,
geometry=geometry,
sources=sources,
symmetries=symmetries)
nfreq = args.nfreq
flux_mon = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0.5*sxy-dpml), size=mp.Vector3(0,sxy-2*dpml,sz-2*dpml)))
sim.run(until_after_sources=100)
res = sim.get_eigenmode_coefficients(flux_mon, [1], eig_parity=mp.ODD_Y)
sim.print_times()
print("mpb-time:, {}".format(sim.time_spent_on(6)[0]))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-hh', type=float, default=0.22, help='wavelength height (default: 0.22 um)')
parser.add_argument('-w', type=float, default=0.50, help='wavelength width (default: 0.50 um)')
parser.add_argument('-nfreq', type=int, default=100, help='number of frequencies')
args = parser.parse_args()
main(args) |
25% isn't very much. How many Newton steps is MPB taking to converge? |
How many Newton steps is that per frequency? |
As shown in the plot below, for this test case master shows ~26 iterations/frequency and this PR is 19 iterations/frequency (which is a difference of ~25%). However and more significantly, if the number of bands (
For comparison, the output from this PR seemed fine:
Thus, it seems that beyond just the speed up enabled by this PR when higher order modes are involved, this PR provides an important fix for making these types of calculations feasible. |
That's still more iterations than I would expect; there might be something wrong with the scaling in the k-point guess here? |
Hmm, that's good news, although I'm not sure why it was so slow before. |
Just in case at some point we want to look into why the mode solver without this patch was failing to converge, the following test case can be used which is based on the original example above and involves a single mode ( When the number of frequencies is <6, the mode solver converges with or without this patch. import meep as mp
import argparse
def main(args):
resolution = args.res
h = 0.22 # waveguide height
w = 0.50 # waveguide width
nSi = 3.45
Si = mp.Medium(index=nSi)
nSiO2 = 1.45
SiO2 = mp.Medium(index=nSiO2)
sxy = 4
sz = 4
cell_size = mp.Vector3(sxy,sxy,sz)
# input waveguide
geometry = [mp.Block(material=Si,
center=mp.Vector3(),
size=mp.Vector3(mp.inf,w,h)),
mp.Block(material=SiO2,
center=mp.Vector3(0,0,-0.5*sz+0.25*(sz-h)),
size=mp.Vector3(mp.inf,mp.inf,0.5*(sz-h)))]
dpml = 1.0
boundary_layers = [mp.PML(dpml)]
# mode frequency
fcen = 1/1.55
# source width
df = 0.2*fcen
sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=df),
component=mp.Ey,
size=mp.Vector3(0,sxy-2*dpml,sz-2*dpml),
center=mp.Vector3(-0.5*sxy+dpml),
eig_match_freq=True,
eig_parity=mp.ODD_Y,
eig_kpoint=mp.Vector3(1.5,0,0))]
symmetries = [mp.Mirror(mp.Y,-1)]
sim = mp.Simulation(resolution=resolution,
cell_size=cell_size,
boundary_layers=boundary_layers,
geometry=geometry,
sources=sources,
symmetries=symmetries)
nfreq = args.nfreq
flux_mon = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0.5*sxy-dpml), size=mp.Vector3(0,sxy-2*dpml,sz-2*dpml)))
sim.run(until_after_sources=100)
res = sim.get_eigenmode_coefficients(flux_mon, [2], eig_parity=mp.ODD_Y)
sim.print_times()
print("mpb-time:, {}".format(sim.time_spent_on(6)[0]))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-res', type=int, default=20, help='resolution (pixels/um)')
parser.add_argument('-nfreq', type=int, default=6, help='number of frequencies')
args = parser.parse_args()
main(args) |
This PR certainly changes the errors slightly because it changes the starting guess, but the accuracy should(?) be no worse than before — that is, the digits that are changing should all be incorrect digits anyway. (No matter how much you decrease the tolerance, at some point MPB will hit an accuracy limit, but this accuracy limit shouldn't(?) be changed by this PR.) |
Implements strategy 1 from #1223.