lumopt2.parametrization.parametrization#

Parametrization - A flexible parametrization class that uses a user-defined function to map optimization parameters (‘p’) to Lumerical geometric object properties (‘P’).

This is the most general and flexible way to parametrize a design in LumOpt2. Instead of implementing specific geometric operations (like the ClosedCurve or Topology), you simply provide a function that maps a parameter vector to a dictionary of object properties that will be set in Lumerical.

Basic Usage Example:
>>> def my_parametrization(params):
>>>     '''Map 3 parameters to cylinder radii'''
>>>     return {
>>>         "cyl0::radius": params[0],
>>>         "cyl1::radius": params[0]+params[1],
>>>         "cyl2::radius": params[0]+params[1]+params[2]
>>>     }
>>> 
>>> parametrization = lmpt.Parametrization(
>>>     func=my_parametrization,
>>>     bounds=[(50e-9, 200e-9)] * 3
>>> )
Example with Mixed Properties:
>>> def mixed_parametrization(params):
>>>     return {
>>>         "waveguide::x": params[0],
>>>         "waveguide::y span": params[1],
>>>         "coupler::radius": params[2],
>>>         "coupler::gap": params[3]
>>>     }
>>> 
>>> parametrization = lmpt.Parametrization(
>>>     func=mixed_parametrization,
>>>     bounds=[(-1e-6, 1e-6), (400e-9, 600e-9), (5e-6, 10e-6), (100e-9, 300e-9)],
>>>     initial_params=[0, 500e-9, 7.5e-6, 200e-9]
>>> )
The property keys should follow Lumerical’s naming convention:

“object_name::property_name”

For example:
  • “rect1::x span”

  • “circle2::radius”

  • “waveguide::y”

More advanced usage could involve vector-valued properties, e.g., “object::vertices” for the vertices of a polygon:

>>> def four_polygon_parametrization(params):
>>>     return {
>>>         f"poly{idx}::vertices": anp.array([[0, value], [value, 0], 
>>>                                            [0, -value], [-value, 0]]) 
>>>         for idx, value in enumerate(params)}
>>>     }
>>> 
>>> parametrization = lmpt.Parametrization(
>>>     func=four_polygon_parametrization,
>>>     bounds=[(100e-9, 300e-9)] * 4,
>>>     initial_params=[200e-9] * 4
>>> )

If the mapping function cannot be tracked by autograd, use the flag use_jac=False. This can happen when the mapping function makes use of third-party libraries or custom code that autograd cannot differentiate through.

Non-differentiable Example:
>>> def nondiff_func_parametrization(params):
>>>     '''Map 5 parameters to cylinder radii using non-differentiable functions'''
>>>     return {
>>>         "cyl0::radius": nondiff_func1(params),
>>>         "cyl1::radius": nondiff_func2(params),
>>>         "cyl2::radius": nondiff_func3(params)
>>>     }
>>>
>>> parametrization = lmpt.Parametrization(
>>>     func=nondiff_func_parametrization,
>>>     bounds=[(50e-9, 200e-9)] * 5,
>>>     initial_params=[200e-9] * 5,
>>>     use_jac=False
>>> )

In this case, the class will assume that each optimization parameter affects all geometric objects in the optimization region for the purposes of the dEps calculation. This is a more conservative assumption that may lead to less efficient gradient calculations, but allows for maximum flexibility in the parametrization.

Classes#

Parametrization(func, bounds, ...[, ...])

Parametrized geometry using a user-defined function to map parameters.