Exemplo n.º 1
0
def test_dumps():
    plan = optplan.OptimizationPlan(
        nodes=[
            optplan.Sum(
                functions=[
                    optplan.Constant(value=optplan.ComplexNumber(real=2)),
                    optplan.Constant(value=optplan.ComplexNumber(real=3)),
                ],)
        ],)

    plan_dict = json.loads(optplan.dumps(plan))
Exemplo n.º 2
0
def test_dumps_duplicate_name_raises_value_error():
    plan = optplan.OptimizationPlan(
        nodes=[
            optplan.Sum(
                functions=[
                    optplan.Constant(
                        name="const", value=optplan.ComplexNumber(real=2)),
                    optplan.Constant(
                        name="const", value=optplan.ComplexNumber(real=3)),
                ],)
        ],)

    with pytest.raises(ValueError, match="Nonunique name found"):
        optplan.dumps(plan)
Exemplo n.º 3
0
class Constant(optplan.Function):
    """Defines a constant scalar.

    Attributes:
        type: Must be "function.constant".
        value: The constant value.
    """

    type = schema_utils.polymorphic_model_type("function.constant")
    value = types.ModelType(optplan.ComplexNumber,
                            default=optplan.ComplexNumber())
Exemplo n.º 4
0
def make_constant(
        value: Union[numbers.Number, optplan.ComplexNumber]) -> Constant:
    """Creates a new constant.

    This is a utility function to quickly create new constants.

    Args:
        value: Value to turn into constant.

    Returns:
        A constant object.
    """
    if isinstance(value, numbers.Number):
        complex_value = complex(value)
        value = optplan.ComplexNumber(real=complex_value.real,
                                      imag=complex_value.imag)
    return Constant(value=value)
Exemplo n.º 5
0
def test_custom_function_node():

    @optplan.register_node_type(optplan.NodeMetaType.OPTPLAN_NODE)
    class CustomOp(optplan.Function):
        type = schema_utils.polymorphic_model_type("custom_op")
        int_val = types.IntType()

    plan = optplan.OptimizationPlan(
        nodes=[
            optplan.Sum(
                functions=[
                    optplan.Constant(value=optplan.ComplexNumber(real=2)),
                    CustomOp(int_val=3),
                ],)
        ],)

    optplan.loads(optplan.dumps(plan))
Exemplo n.º 6
0
def test_get_mat_index_from_index():
    mat = optplan.Material(index=optplan.ComplexNumber(real=2, imag=3))
    assert _get_mat_index(mat) == 2 + 3j
Exemplo n.º 7
0
def test_constant_standard():
    """Tests `make_constant` creation using standard procedure."""
    constant = optplan.make_constant(
        value=optplan.ComplexNumber(real=2, imag=3.4))
    assert constant.value.real == 2
    assert constant.value.imag == 3.4
Exemplo n.º 8
0
def create_sim_space(
    gds_fg_name: str,
    gds_bg_name: str,
    sim_width: float = 8000,  # size of sim_space
    box_width: float = 4000,  # size of our editing structure
    wg_width: float = 600,
    buffer_len: float = 1500,  # not sure we'll need
    dx: int = 40,
    num_pmls: int = 10,
    visualize: bool = False,
) -> optplan.SimulationSpace:
    """Creates the simulation space.

    The simulation space contains information about the boundary conditions,
    gridding, and design region of the simulation.

    Args:
        gds_fg_name: Location to save foreground GDS.
        gds_bg_name: Location to save background GDS.
        etch_frac: Etch fraction of the grating. 1.0 indicates a fully-etched
            grating.
        box_thickness: Thickness of BOX layer in nm.
        wg_width: Width of the waveguide.
        buffer_len: Buffer distance to put between grating and the end of the
            simulation region. This excludes PMLs.
        dx: Grid spacing to use.
        num_pmls: Number of PML layers to use on each side.
        visualize: If `True`, draws the polygons of the GDS file.

    Returns:
        A `SimulationSpace` description.
    """
    # Calculate the simulation size, including  PMLs
    # TODO change the first part of ech dimension to be equal
    sim_size = [
        sim_width + 2 * buffer_len + dx * num_pmls,
        sim_width + 2 * buffer_len + dx * num_pmls
    ]
    # First, we use `gdspy` to draw the waveguides and shapes that we would
    # like to use. Instead of programmatically generating a GDS file using
    # `gdspy`, we could also simply provide a GDS file (e.g. drawn using
    # KLayout).

    # Declare some constants to represent the different layers.
    # Not sure if we need layers
    LAYER = 100

    # Create rectangles corresponding to the waveguide, the BOX layer, and the
    # design region. We extend the rectangles outside the simulation region
    # by multiplying locations by a factor of 1.1.

    # We distinguish between the top part of the waveguide (which is etched)
    # and the bottom part of the waveguide (which is not etched).

    # TODO define our single waveguide and surface, I don't believe it will be etched.
    # Switch x and y temporarily to try and get better direction for field - change top to bottom
    # Add an exit
    waveguide_top = gdspy.Rectangle((-1.1 * sim_size[0] / 2, -wg_width / 2),
                                    (-box_width / 2, wg_width / 2), LAYER)

    waveguide_bottom = gdspy.Rectangle((box_width / 2, -wg_width / 2),
                                       (1.1 * sim_size[0] / 2, wg_width / 2),
                                       LAYER)

    design_region = gdspy.Rectangle(
        (-box_width / 2, -box_width / 2),
        (box_width / 2, box_width / 2),  # extend region?
        LAYER)

    # Generate the foreground and background GDS files.
    gds_fg = gdspy.Cell("FOREGROUND", exclude_from_current=True)
    gds_fg.add(waveguide_top)
    gds_fg.add(waveguide_bottom)
    gds_fg.add(design_region)

    # I guess we keep this the same and not include the design_region
    gds_bg = gdspy.Cell("BACKGROUND", exclude_from_current=True)
    gds_bg.add(waveguide_top)
    gds_bg.add(waveguide_bottom)

    gdspy.write_gds(gds_fg_name, [gds_fg], unit=1e-9, precision=1e-9)
    gdspy.write_gds(gds_bg_name, [gds_bg], unit=1e-9, precision=1e-9)

    # The BOX layer/silicon device interface is set at `z = 0`.
    #
    # Describe materials in each layer.

    # 1) Silicon Nitride

    # Note that the layer numbering in the GDS file is arbitrary. Layer 300 is a dummy
    # layer; it is used for layers that only have one material (i.e. the
    # background and foreground indices are identical) so the actual structure
    # used does not matter.

    # Will need to define out material, just silicon nitride
    # Remove the etching stuff
    # Can define Si3N4 - the material we want to use
    # Fix: try to make multiple layers, but all the same?
    air = optplan.Material(index=optplan.ComplexNumber(real=1))
    stack = [
        optplan.GdsMaterialStackLayer(
            foreground=air,
            background=air,
            gds_layer=[100, 0],
            extents=[
                -10000, -110
            ],  # will probably need to define a better thickness for our layer
        ),
        optplan.GdsMaterialStackLayer(
            foreground=optplan.Material(mat_name="Si3N4"),
            background=air,
            gds_layer=[100, 0],
            extents=[
                -110, 110
            ],  # will probably need to define a better thickness for our layer
        ),
    ]

    mat_stack = optplan.GdsMaterialStack(
        # Any region of the simulation that is not specified is filled with
        # air.
        background=air,
        stack=stack,
    )

    # these define the entire region you wish to scan in the z -direction, not sure for us
    # as we don't require etching or layers
    # will probably change this as thickness may be wrong

    # Create a simulation space for both continuous and discrete optimization.
    # TODO too large a space takes too long to process - may need blue bear
    simspace = optplan.SimulationSpace(
        name="simspace",
        mesh=optplan.UniformMesh(dx=dx),
        eps_fg=optplan.GdsEps(gds=gds_fg_name, mat_stack=mat_stack),
        eps_bg=optplan.GdsEps(gds=gds_bg_name, mat_stack=mat_stack),
        # Note that we explicitly set the simulation region. Anything
        # in the GDS file outside of the simulation extents will not be drawn.
        sim_region=optplan.Box3d(
            center=[0, 0, 0],
            extents=[6000, 6000,
                     40],  # this is what's messing things up, needs to be 2D
        ),  # changing the size too much creates an error
        selection_matrix_type="direct_lattice",  # or uniform
        # PMLs are applied on x- and z-axes. No PMLs are applied along y-axis
        # because it is the axis of translational symmetry.
        pml_thickness=[num_pmls, num_pmls, num_pmls, num_pmls, 0,
                       0],  # may need to edit this, make z the 0 axis
    )

    if visualize:
        # To visualize permittivity distribution, we actually have to
        # construct the simulation space object.
        import matplotlib.pyplot as plt
        from spins.invdes.problem_graph.simspace import get_fg_and_bg

        context = workspace.Workspace()
        eps_fg, eps_bg = get_fg_and_bg(context.get_object(simspace),
                                       label=1070)  #edit here

        def plot(x):
            plt.imshow(np.abs(x)[:, 0, :].T.squeeze(), origin="lower")

        plt.figure()
        plt.subplot(3, 1, 1)
        plot(eps_fg[2])
        plt.title("eps_fg")

        plt.subplot(3, 1, 2)
        plot(eps_bg[2])
        plt.title("eps_bg")

        plt.subplot(3, 1, 3)
        plot(eps_fg[2] - eps_bg[2])
        plt.title("design region")
        plt.show()
    return simspace
Exemplo n.º 9
0
def create_sim_space(gds_fg: str, gds_bg: str) -> optplan.SimulationSpace:
    """Creates the simulation space.

    The simulation space contains information about the boundary conditions,
    gridding, and design region of the simulation. The material stack is
    220 nm of silicon surrounded by oxide. The refractive index of the silicon
    changes based on whether the global viarble `SIM_2D` is set.

    Args:
        gds_fg: Location of the foreground GDS file.
        gds_bg: Location of the background GDS file.

    Returns:
        A `SimulationSpace` description.
    """
    mat_oxide = optplan.Material(index=optplan.ComplexNumber(real=1.5))
    if SIM_2D:
        device_index = SI_2D_INDEX
    else:
        device_index = SI_3D_INDEX

    mat_stack = optplan.GdsMaterialStack(
        background=mat_oxide,
        stack=[
            optplan.GdsMaterialStackLayer(
                foreground=mat_oxide,
                background=mat_oxide,
                gds_layer=[100, 0],
                extents=[-10000, -110],
            ),
            optplan.GdsMaterialStackLayer(
                foreground=optplan.Material(index=optplan.ComplexNumber(
                    real=device_index)),
                background=mat_oxide,
                gds_layer=[100, 0],
                extents=[-110, 110],
            ),
        ],
    )

    if SIM_2D:
        # If the simulation is 2D, then we just take a slice through the
        # device layer at z = 0. We apply periodic boundary conditions along
        # the z-axis by setting PML thicknes to zero.
        sim_region = optplan.Box3d(center=[0, 0, 0],
                                   extents=[5000, 5000, GRID_SPACING])
        pml_thickness = [10, 10, 10, 10, 0, 0]
    else:
        sim_region = optplan.Box3d(center=[0, 0, 0],
                                   extents=[5000, 5000, 2000])
        pml_thickness = [10, 10, 10, 10, 10, 10]

    return optplan.SimulationSpace(
        name="simspace_cont",
        mesh=optplan.UniformMesh(dx=GRID_SPACING),
        eps_fg=optplan.GdsEps(gds=gds_fg, mat_stack=mat_stack),
        eps_bg=optplan.GdsEps(gds=gds_bg, mat_stack=mat_stack),
        sim_region=sim_region,
        selection_matrix_type="direct_lattice",
        boundary_conditions=[optplan.BlochBoundary()] * 6,
        pml_thickness=pml_thickness,
    )
Exemplo n.º 10
0
def create_sim_space(gds_fg_name: str,
                     gds_bg_name: str,
                     wg_thickness: float = 220,
                     wg_length: float = 3000,
                     wg_width: float = 200,
                     buffer_len: float = 250,
                     dx: int = 40,
                     num_pmls: int = 10) -> optplan.SimulationSpace:
    """Creates the simulation space.

    The simulation space contains information about the boundary conditions,
    gridding, and design region of the simulation.

    Args:
        gds_fg_name: Location to save foreground GDS.
        gds_bg_name: Location to save background GDS.
        wg_thickness: Thickness of the waveguide.
        dx: Grid spacing to use.
        num_pmls: Number of PML layers to use on each side.

    Returns:
        A `SimulationSpace` description.
    """

    sim_size = wg_length + buffer_len * 2

    waveguide_input = gdspy.Rectangle((-sim_size / 2, -wg_width / 2),
                                      (-wg_length / 2, wg_width / 2), 100)
    waveguide_output = gdspy.Rectangle((-wg_width / 2, -sim_size / 2),
                                       (wg_width / 2, -wg_length / 2), 100)
    design_region = gdspy.Rectangle((-wg_length / 2, -wg_length / 2),
                                    (wg_length / 2, wg_length / 2), 100)

    gds_fg = gdspy.Cell("FOREGROUND", exclude_from_current=True)
    gds_fg.add(waveguide_input)
    gds_fg.add(waveguide_output)
    gds_fg.add(design_region)

    gds_bg = gdspy.Cell("BACKGROUND", exclude_from_current=True)
    gds_bg.add(waveguide_input)
    gds_bg.add(waveguide_output)

    gdspy.write_gds(gds_fg_name, [gds_fg], unit=1e-9, precision=1e-9)
    gdspy.write_gds(gds_bg_name, [gds_bg], unit=1e-9, precision=1e-9)

    mat_oxide = optplan.Material(index=optplan.ComplexNumber(real=1.45))
    stack = [
        optplan.GdsMaterialStackLayer(
            foreground=mat_oxide,
            background=mat_oxide,
            gds_layer=[100, 0],
            extents=[-wg_length * 3, -wg_thickness / 2],
        ),
        optplan.GdsMaterialStackLayer(
            foreground=optplan.Material(index=optplan.ComplexNumber(real=1.5)),
            background=mat_oxide,
            gds_layer=[100, 0],
            extents=[-wg_thickness / 2, wg_thickness / 2],
        ),
    ]

    mat_stack = optplan.GdsMaterialStack(
        # Any region of the simulation that is not specified is filled with
        # oxide.
        background=mat_oxide,
        stack=stack,
    )

    # Create a simulation space for both continuous and discrete optimization.
    simspace = optplan.SimulationSpace(
        name="simspace",
        mesh=optplan.UniformMesh(dx=dx),
        eps_fg=optplan.GdsEps(gds=gds_fg_name, mat_stack=mat_stack),
        eps_bg=optplan.GdsEps(gds=gds_bg_name, mat_stack=mat_stack),
        sim_region=optplan.Box3d(
            center=[0, 0, 0],
            extents=[wg_length * 2, wg_length * 2, dx],
        ),
        selection_matrix_type="direct_lattice",
        pml_thickness=[num_pmls, num_pmls, num_pmls, num_pmls, 0, 0],
    )

    return simspace
Exemplo n.º 11
0
def create_sim_space(
        gds_fg_name: str,
        gds_bg_name: str,
        sim_width: float = 8000,  # size of sim_space
        box_width: float = 4000,  # size of our editing structure
        wg_width: float = 500,
        buffer_len: float = 1500,  # not sure we'll need
        dx: int = 40,
        num_pmls: int = 10,
        visualize: bool = False,
) -> optplan.SimulationSpace:
    """Creates the simulation space.

    The simulation space contains information about the boundary conditions,
    gridding, and design region of the simulation.

    Args:
        gds_fg_name: Location to save foreground GDS.
        gds_bg_name: Location to save background GDS.
        etch_frac: Etch fraction of the grating. 1.0 indicates a fully-etched
            grating.
        box_thickness: Thickness of BOX layer in nm.
        wg_width: Width of the waveguide.
        buffer_len: Buffer distance to put between grating and the end of the
            simulation region. This excludes PMLs.
        dx: Grid spacing to use.
        num_pmls: Number of PML layers to use on each side.
        visualize: If `True`, draws the polygons of the GDS file.

    Returns:
        A `SimulationSpace` description.
    """

    # The BOX layer/silicon device interface is set at `z = 0`.
    #
    # Describe materials in each layer.

    # 1) Silicon Nitride

    # Note that the layer numbering in the GDS file is arbitrary. Layer 300 is a dummy
    # layer; it is used for layers that only have one material (i.e. the
    # background and foreground indices are identical) so the actual structure
    # used does not matter.

    # Will need to define out material, just silicon nitride
    # Remove the etching stuff
    # Can define Si3N4 - the material we want to use
    # Fix: try to make multiple layers, but all the same?

    air = optplan.Material(mat_name="air")
    quartz = optplan.Material(index=optplan.ComplexNumber(real=2.10))
    stack = [
        optplan.GdsMaterialStackLayer(
            foreground=quartz,
            background=quartz,
            gds_layer=[100, 0],
            extents=[-10000, -110],  # will probably need to define a better thickness for our layer
        ),
        optplan.GdsMaterialStackLayer(
            foreground=optplan.Material(index=optplan.ComplexNumber(real=SI_2D_INDEX)),
            background=air,
            gds_layer=[100, 0],
            extents=[-110, 110],  # will probably need to define a better thickness for our layer
        ),
    ]

    mat_stack = optplan.GdsMaterialStack(
        # Any region of the simulation that is not specified is filled with
        # air.
        background=air,
        stack=stack,
    )

    # these define the entire region you wish to scan in the z -direction, not sure for us
    # as we don't require etching or layers
    # will probably change this as thickness may be wrong

    # Create a simulation space for both continuous and discrete optimization.
    simspace = optplan.SimulationSpace(
        name="simspace",
        mesh=optplan.UniformMesh(dx=dx),
        eps_fg=optplan.GdsEps(gds=gds_fg_name, mat_stack=mat_stack),
        eps_bg=optplan.GdsEps(gds=gds_bg_name, mat_stack=mat_stack),
        # Note that we explicitly set the simulation region. Anything
        # in the GDS file outside of the simulation extents will not be drawn.
        sim_region=optplan.Box3d(
            center=[0, 0, 0],
            extents=[13500, 3350, dx],
        ),
        selection_matrix_type="direct_lattice",  # or uniform
        # PMLs are applied on x- and z-axes. No PMLs are applied along y-axis
        # because it is the axis of translational symmetry.
        pml_thickness=[num_pmls, num_pmls, num_pmls, num_pmls, 0, 0],  # may need to edit this, make z the 0 axis
    )

    if visualize:
        # To visualize permittivity distribution, we actually have to
        # construct the simulation space object.
        import matplotlib.pyplot as plt
        from spins.invdes.problem_graph.simspace import get_fg_and_bg

        context = workspace.Workspace()
        eps_fg, eps_bg = get_fg_and_bg(context.get_object(simspace), wlen=1425)  # edit here

        def plot(x):
            plt.imshow(np.abs(x)[:, 0, :].T.squeeze(), origin="lower")

        plt.figure()
        plt.subplot(3, 1, 1)
        plot(eps_fg[2])
        plt.title("eps_fg")

        plt.subplot(3, 1, 2)
        plot(eps_bg[2])
        plt.title("eps_bg")

        plt.subplot(3, 1, 3)
        plot(eps_fg[2] - eps_bg[2])
        plt.title("design region")
        plt.show()
    return simspace