HomerReid/meep_adjoint

Console Manager issues

Opened this issue · 1 comments

I've noticed the new console manager tends to get in the way of meep's geometry initialization. Plus it makes it difficult to debug since it hides all the output to the console.

I'll work on posting a MWE to give more specifics -- just wanted to give you a heads up now while you're working on things.

Here's a MWE:

import sys
import os
import argparse

import numpy as np
import meep as mp

import meep_adjoint

from meep_adjoint import get_adjoint_option as adj_opt
from meep_adjoint import get_visualization_option as vis_opt

from meep_adjoint import ( OptimizationProblem, Subregion,
                           ORIGIN, XHAT, YHAT, ZHAT, E_CPTS, H_CPTS, v3, V3)

from matplotlib import pyplot as plt
from scipy.optimize import minimize

######################################################################
# override meep_adjoint's default settings for some configuration opts
######################################################################
meep_adjoint.set_option_defaults( { 'fcen': 0.5, 'df': 0.2,
                                    'dpml': 1.0, 'dair': 0.5,
                                    'eps_func': 6.0 })


# fetch values of meep_adjoint options that we will use below
fcen = adj_opt('fcen')
dpml = adj_opt('dpml')
dair = adj_opt('dair')


######################################################################
# handle problem-specific command-line arguments
######################################################################
parser = argparse.ArgumentParser()

# options affecting the geometry of the cross-router
parser.add_argument('--wh',       type=float, default=1.5,  help='width of horizontal waveguide')
parser.add_argument('--wv',       type=float, default=1.5,  help='width of vertical waveguide')
parser.add_argument('--h',        type=float, default=0.0,  help='height of waveguide in z-direction')
parser.add_argument('--l_stub',   type=float, default=3.0,  help='waveguide input/output stub length')
parser.add_argument('--l_design', type=float, default=4.0,  help='design region side length')
parser.add_argument('--eps_wvg',  type=float, default=6.0,  help='waveguide permittivity')

# basis-set options
parser.add_argument('--element_length',  type=float,  default=0.25,       help='finite-element length scale')
parser.add_argument('--element_type',    type=str,    default='Lagrange', help='finite-element type')
parser.add_argument('--element_order',   type=int,    default=1,          help='finite-element order')

# configurable weighting prefactors for the north, south, and east power fluxes
# to allow the objective function to be redefined via command-line options
parser.add_argument('--n_weight', type=float, default=1.00, help='')
parser.add_argument('--s_weight', type=float, default=0.00, help='')
parser.add_argument('--e_weight', type=float, default=0.00, help='')

args = parser.parse_args()


##################################################
# set up optimization problem
##################################################


#----------------------------------------
# size of computational cell
#----------------------------------------
lcen          = 1.0/fcen
dpml          = 0.5*lcen if dpml == -1.0 else dpml
design_length = args.l_design
sx = sy       = dpml + args.l_stub + design_length + args.l_stub + dpml
sz            = 0.0 if args.h==0.0 else dpml + dair + args.h + dair + dpml
cell_size     = [sx, sy, sz]

#----------------------------------------------------------------------
#- geometric objects (material bodies), not including the design object
#----------------------------------------------------------------------
wvg_mat = mp.Medium(epsilon=args.eps_wvg)
hwvg = mp.Block(center=V3(ORIGIN), material=wvg_mat, size=V3(sx, args.wh, sz) )
vwvg = mp.Block(center=V3(ORIGIN), material=wvg_mat, size=V3(args.wv, sy, sz) )

#----------------------------------------------------------------------
#- objective regions
#----------------------------------------------------------------------
d_flux     = 0.5*(design_length + args.l_stub)  # distance from origin to NSEW flux monitors
gap        = args.l_stub/6.0                    # gap between source region and flux monitor
d_source   = d_flux + gap                       # distance from origin to source
d_flx2     = d_flux + 2.0*gap

n_center   = ORIGIN + d_flux*YHAT
s_center   = ORIGIN - d_flux*YHAT
e_center   = ORIGIN + d_flux*XHAT
w1_center  = ORIGIN - d_flux*XHAT
w2_center  = w1_center - 2.0*gap*XHAT

ns_size    = [2.0*args.wh, 0.0, sz]
ew_size    = [0.0, 2.0*args.wv, sz]

north      = Subregion(center=n_center, size=ns_size, dir=mp.Y,  name='north')
south      = Subregion(center=s_center, size=ns_size, dir=mp.Y,  name='south')
east       = Subregion(center=e_center, size=ew_size, dir=mp.X,  name='east')
west1      = Subregion(center=w1_center, size=ew_size, dir=mp.X, name='west1')
west2      = Subregion(center=w2_center, size=ew_size, dir=mp.X, name='west2')

#----------------------------------------------------------------------
# objective function and extra objective quantities -------------------
#----------------------------------------------------------------------
n_term = '{}*Abs(P1_north)**2'.format(args.n_weight) if args.n_weight else ''
s_term = '{}*Abs(S1_south)**2'.format(args.s_weight) if args.s_weight else ''
e_term = '{}*Abs(P1_east)**2'.format(args.e_weight) if args.e_weight else ''

objective = n_term + s_term + e_term
extra_quantities = ['S_north', 'S_south', 'S_east', 'S_west1', 'S_west2']

#----------------------------------------------------------------------
# source region
#----------------------------------------------------------------------
source_center  = ORIGIN - d_source*XHAT
source_size    = ew_size
source_region  = Subregion(center=source_center, size=source_size, name=mp.X)

#----------------------------------------------------------------------
#- design region, expansion basis
#----------------------------------------------------------------------
design_center = ORIGIN
design_size   = [design_length, design_length, sz]
design_region = Subregion(name='design', center=design_center, size=design_size)

#----------------------------------------
#- optional extra regions for visualization
#----------------------------------------
full_region = Subregion(name='full', center=ORIGIN, size=cell_size)


#----------------------------------------------------------------------
#----------------------------------------------------------------------
#----------------------------------------------------------------------
opt_prob = OptimizationProblem(objective_regions=[north, south, east, west1, west2],
                               objective_function=objective,
                               design_region=design_region,
                               cell_size=cell_size, 
                               background_geometry=[hwvg, vwvg],
                               source_region=source_region,
                               extra_quantities=extra_quantities, 
                               extra_regions=[full_region])

f, df = opt_prob.get_fdf_funcs()
    
    
def J(x,info):
    plt.figure()
    opt_prob.stepper.sim.plot2D()
    filename = 'optiter_{}.png'.format(info['Nfeval'])
    plt.savefig(filename)
    plt.close('all')
    info['Nfeval'] += 1
    return -f(x)

def dJ(x,info):
    return df(x)

n = opt_prob.basis.dim
x0 = 3*np.ones((n,))
maxiter = 100
res = minimize(J, x0, args=({'Nfeval':0},), method='CG', jac=dJ, options={'maxiter':maxiter, 'disp': True})

Here's the output:

python3 CrossRouter.py
Using MPI version 3.1, 1 processes
/home/alechammond/GitHub/meep_adjoint/meep_adjoint/optimization_problem.py:230: UserWarning: forward run not yet run for this design; ignoring request to omit
  warnings.warn('forward run not yet run for this design; ignoring request to omit')
/home/alechammond/GitHub/meep_adjoint/meep_adjoint/util.py:44: UserWarning: failed to launch dashboard server:<class 'AttributeError'>
Exception value: module 'contextlib' has no attribute 'nullcontext'
  File "/home/alechammond/GitHub/meep_adjoint/meep_adjoint/dashboard_client.py", line 149, in fork_dashboard_server
    cm = contextlib.nullcontext(subprocess.DEVNULL)

  warnings.warn(msg)
/home/alechammond/GitHub/meep_adjoint/meep_adjoint/util.py:44: UserWarning: failed to connect to dashboard server:<class 'ConnectionRefusedError'>
Exception value: [Errno 111] Connection refused
  File "/home/alechammond/GitHub/meep_adjoint/meep_adjoint/dashboard_client.py", line 68, in launch_dashboard
    dashboard_socket.connect( (host, port) )

  warnings.warn(msg)
forward  SOURCES    0.0 -> t ->  50.0
forward  CONV 1   [ 50.0 -> t ->  62.5]  delta 1.00e+09
on time step 2013 (time=50.325), 0.00198742 s/step
on time step 4023 (time=100.575), 0.00199028 s/step
forward  CONV 2   [ 62.5 -> t ->  75.0]  delta 4.05e-02
on time step 5986 (time=149.65), 0.00203774 s/step
adjoint  SOURCES    0.0 -> t ->  50.0
adjoint  CONV 1   [ 50.0 -> t ->  62.5]  delta 1.00e+09
adjoint  CONV 2   [ 62.5 -> t ->  75.0]  delta 1.05e-01
Traceback (most recent call last):
  File "CrossRouter.py", line 165, in <module>
    res = minimize(J, x0, args=({'Nfeval':0},), method='CG', jac=dJ, options={'maxiter':maxiter, 'disp': True})
  File "/home/alechammond/miniconda3/envs/pmp/lib/python3.6/site-packages/scipy/optimize/_minimize.py", line 592, in minimize
    return _minimize_cg(fun, x0, args, jac, callback, **options)
  File "/home/alechammond/miniconda3/envs/pmp/lib/python3.6/site-packages/scipy/optimize/optimize.py", line 1303, in _minimize_cg
    old_fval = f(xk)
  File "/home/alechammond/miniconda3/envs/pmp/lib/python3.6/site-packages/scipy/optimize/optimize.py", line 326, in function_wrapper
    return function(*(wrapper_args + args))
  File "CrossRouter.py", line 157, in J
    return -f(x)
  File "/home/alechammond/GitHub/meep_adjoint/meep_adjoint/optimization_problem.py", line 255, in _f
    (fq, _) = self.__call__(beta_vector = x, need_gradient = False)
  File "/home/alechammond/GitHub/meep_adjoint/meep_adjoint/optimization_problem.py", line 238, in __call__
    fq    = self.stepper.run('forward') if need_value else None
  File "/home/alechammond/GitHub/meep_adjoint/meep_adjoint/timestepper.py", line 178, in run
    self.prepare(job)
  File "/home/alechammond/GitHub/meep_adjoint/meep_adjoint/timestepper.py", line 290, in prepare
    self.sim.init_sim()
  File "/home/alechammond/miniconda3/envs/pmp/lib/python3.6/site-packages/meep/simulation.py", line 1169, in init_sim
    self._init_structure(self.k_point)
  File "/home/alechammond/miniconda3/envs/pmp/lib/python3.6/site-packages/meep/simulation.py", line 1081, in _init_structure
    None
RuntimeError: meep: Error in typemaps

Elapsed run time = 21.5917 s
Attempting to use an MPI routine after finalizing MPICH

The problem appears to be dependent on the optimizer I use. Perhaps something to do with the order it tries to call just for the gradient?

Like I said, it's hard to debug because the console manager hides any print statements. If I proceed without the console manager (i.e. I comment it out) found here:

with ConsoleManager() as cm:
fq = self.stepper.run('forward') if need_value else None
gradf = self.stepper.run('adjoint') if need_gradient else None

then there's no issue.