Components

DeviceLayout.AbstractComponentType
abstract type AbstractComponent{T} <: GeometryStructure{T}

A parameterized layout element, to be used as a building block in schematic-driven design.

The alias Component = AbstractComponent{typeof(1.0nm)} is provided for convenience.

Each AbstractComponent comes with the necessary parameters and methods to render its geometry and to attach it to other components in a schematic. Something similar to this concept may be familiar from other electronic design automation tools as a PCell ("parameterized cell").

You might call something a component if you would include it in a schematic or diagram rather than abstracting it away, if it can be described as a black box with ports, or if you might want to simulate it independently. For example, a series interdigital capacitor could be defined as a AbstractComponent, with attachment points (Hooks) at the end of each lead.

AbstractComponents provide a common interface:

  • name(c::MyComponent): The name of the component.
  • parameters(c::MyComponent): The parameters of the component as a NamedTuple.
  • geometry(c::MyComponent): A coordinate system containing c's rendered geometry.
  • hooks(c::MyComponent): A NamedTuple of Hooks and Hook arrays that specify how connections are made with c.
  • hooks(c::MyComponent, h::Symbol): The specific hook identified by h.
  • default_parameters(c::Union{MyComponent, Type{MyComponent}}): Default parameters as a NamedTuple.
  • parameter_names(c::Union{MyComponent, Type{MyComponent}}): Parameter names as a collection of Symbols.
  • A keyword constructor that merges keyword arguments into default_parameters non-recursively. (That is, a NamedTuple keyword argument will overwrite the default parameter entirely, meaning every "subparameter" in the NamedTuple needs to be specified.)
  • create_component(::Type{MyComponent}, name::String=default_parameters(MyComponent).name, base_parameters::NamedTuple=default_parameters(MyComponent); kwargs...): Constructor that recursively merges kwargs into base_parameters. (That is, a NamedTuple keyword argument will be merged into the corresponding NamedTuple base parameter, meaning not every "subparameter" needs to be fully specified.)
  • set_parameters(mycomp::MyComponent, name::String=name(mycomp), params::NamedTuple=parameters(c); kwargs...): Shorthand for create_component using mycomp for base parameters
  • (mycomp::MyComponent)(name::String=name(mycomp), params::NamedTuple=parameters(mycomp)=; kwargs...): Shorter shorthand for the above

Since AbstractComponent is a subtype of GeometryStructure, they can also be referenced by a StructureReference. Other GeometryStructure interface methods, including elements, element_metadata, refs, flatten, footprint, halo, and transform operate on geometry(mycomp).

The name of a component is not guaranteed to be unique. Instances of components within schematics as well as coordinate systems within a layout will always have unique identifiers, which are automatically constructed from a component's name using uniquename if it is not already unique. For this reason, it is often best for designers to give important components unique names, guaranteeing that the corresponding identifiers are the same.

source
DeviceLayout.SchematicDrivenLayout.ComponentType
const Component = AbstractComponent{typeof(1.0UPREFERRED)}

Component is an alias for AbstractComponent with the coordinate type typeof(1.0UPREFERRED).

DeviceLayout.UPREFERRED is a constant set according to the unit preference in Project.toml or LocalPreferences.toml. The default ("PreferNanometers") gives const UPREFERRED = DeviceLayout.nm, with mixed-unit operations preferring conversion to nm.

source

Defining components

The recommended way to define a component is the @compdef macro, which specifies the parameters names and defaults as part of the struct definition. It creates the keyword constructor (like Base.@kwdef does) as well as the default_parameters method that are required to allow the above interface to work.

DeviceLayout.SchematicDrivenLayout.@compdefMacro
@compdef typedef

This is a helper macro that extends Base.@kwdef, which automatically defines a keyword-based constructor for the type declared in the expression typedef, which must be a struct or mutable struct expression. The default argument is supplied by declaring fields of the form field::T = default or field = default. If no default is provided then the keyword argument becomes a required keyword argument in the resulting type constructor. Inner constructors can still be defined, but at least one should accept arguments in the same form as the default inner constructor (i.e. one positional argument per field) in order to function correctly with the keyword outer constructor.

This generates a default_parameters method for the defined type, which returns the default parameters as a NamedTuple. If any parameters are required (have no default), they do not appear in default_parameters.

The new type will also have a _geometry field for caching geometry, or _graph and _schematic fields for composite components. Note that if you want to use your own abstract composite supertype you should define SchematicDrivenLayout.iscomposite(::Val{:MyAbstractCompositeComponent}) = true.

Examples

julia> @compdef struct MyComp <: Component
           name::String = "mycomp"
           a::Int = 1         # specified default
           b::String          # required keyword
       end

julia> default_parameters(MyComp)
(name = "mycomp", a = 1)
source

An AbstractComponent should include a name field, and also implement the following specializations:

  • _geometry!(cs::CoordinateSystem, comp::MyComponent): Render the component's geometry to a CoordinateSystem cs.
  • hooks(::MyComponent): a NamedTuple of Hooks and/or Vector{Hook}s that specify where and how attachments are made

Validation or reconciling of parameters should be done in an inner constructor. At least one inner constructor should accept arguments in the same form as the default inner constructor (i.e. one positional argument per field) in order to function correctly with the keyword outer constructor.

An AbstractComponent may also override GeometryStructure methods like footprint and halo.

The methods check_rotation and allowed_rotation_angles can be implemented to enforce a requirement for the orientation of the component in the global coordinate system:

DeviceLayout.SchematicDrivenLayout.check_rotationFunction
check_rotation(::AbstractComponent)

Determines whether the global orientation of a component will be checked by check!(::Schematic). check_rotation(::AbstractComponent) returns false, so any components of type T requiring rotation checks must overload this method as check_rotation(::T) = true. Checkable components must also overload the method allow_rotation_angles(::T).

source
DeviceLayout.SchematicDrivenLayout.allowed_rotation_anglesFunction
allowed_rotation_angles(::AbstractComponent)

Return a vector of allowed rotation angles. If the net rotation of a component in a planned Schematic (the rotation of its native axes relative to the axes of the global coordinate system) matches a number in this list, the component passes the check.

source

Finally, an AbstractComponent may define methods to specify default hooks for fusion with other components in a schematic:

  • matching_hooks(::MyComponent1, ::MyComponent2)
  • matching_hooks(::MyComponent2, ::MyComponent1)
  • matching_hook(::MyComponent1, hook1::Symbol, ::MyComponent2)
  • ...

Methods for both argument orders in matching_hooks should generally be defined. Although SchematicGraphs are undirected, certain components may treat the different argument orders differently. For example, matching_hooks(::Path, <:AbstractComponent) will attach the second argument to the endpoint hook :p1 on the Path, while the reverse order will attach the start point hook :p0 to the first argument.

Components support the following API:

DeviceLayout.SchematicDrivenLayout.geometryFunction
geometry(comp::AbstractComponent)

A CoordinateSystem containing the AbstractComponent's geometry with metadata.

The result for each unique comp (by ===) is memoized.

The result has result.name == uniquename(name(comp)).

source
geometry(cc:AbstractCompositeComponent)

Return the CoordinateSystem resulting from build!(plan(graph(cc))).

source
DeviceLayout.hooksFunction
hooks(pa::Path)
  • :p0: A HandedPointHook looking into the start of path pa.
  • :p1: A HandedPointHook looking into the end of path pa.
  • :p0_lh: A left-handed HandedPointHook looking into the start of path pa.
  • :p1_lh: A left-handed HandedPointHook looking into the end of path pa.
source
hooks(rres::ExampleClawedMeanderReadout)

Hooks for attaching a readout resonator claw to a qubit and coupling section to a feedline.

  • qubit: The "palm" of the claw on the outside edge of the "shield". Matches (eq::ExampleRectangleTransmon) => :rres.
  • feedline: A distance coupling_gap from the edge of the ground plane, vertically aligned with the claw.
source
hooks(sch::Schematic, node::ComponentNode)

The hooks belonging to the component in node in the global coordinate system of sch.

source
hooks(comp::AbstractComponent)

A component's Hooks (a set of locations and rules for attaching to other components).

Returns a NamedTuple of Hooks and/or arrays of Hooks for a AbstractComponent instance. To access a Hook directly whether or not it's in an array, use hooks(::AbstractComponent, ::Symbol).

source
hooks(comp::AbstractComponent, h::Symbol)

A component's Hook identified by h.

Preferred way to retrieve a hook over accessing the NamedTuple directly (hooks(comp).h). Allows access to hooks in arrays by interpreting :hookname_i as hooks(comp).hookname[i] if :hookname_i is not itself a key in hooks(comp).

source
hooks(cc::AbstractCompositeComponent)

Hooks for the composite geometry, placed at corresponding hooks of the subcomponents.

Hooks

A hook hcc is returned for each hook (name h) of every subcomponent node (index i). If keys(map_hooks(cc)) contains i => h, then the corresponding composite hook is map_hooks(cc)[h]. Otherwise, it is _$(i)_$h.

source
hooks(cc::AbstractCompositeComponent, subcompname::String, h::Symbol)

Attempts to retrieve the composite hook corresponding to hook h of a Component with name subcompname (either its unique name or its name parameters). Will emit an error if the name is ambiguous.

source
hooks(cc::AbstractCompositeComponent, i::Int, h::Symbol)
hooks(cc::AbstractCompositeComponent, (i=>h)::Pair{Int, Symbol})

The composite hook corresponding to hook h of components(cc)[i].

source
hooks(::ExampleRectangleTransmon)

Hooks for attaching control lines and readout to the transmon.

  • readout: The center edge of the ground plane on the opposite side of the island from the SQUID.
  • xy: The left side of the capacitor gap.
  • z: The center edge of the ground plane in the SQUID loop.
source
DeviceLayout.haloMethod
halo(c::AbstractComponent, delta, inner_delta=nothing; only_layers=[], ignore_layers=[])

A component's halo, intended for use as an exclusion zone parameterized by a bias delta.

By default, this applies a delta halo to all geometry elements whose metadata matches the inclusion/exclusion requirements. For example, polygons are offset by delta (enlarged by growing delta away from each original edge). Any entities in layers in ignore_layers will be skipped. If only_layers is not empty, only those layers will be used to generate the halo. Layers for inclusion and exclusion can be provided as layer name Symbols, in which case only the layer name needs to be matched, or as full DeviceLayout.Meta objects, in which case all metadata fields (e.g., index and level for SemanticMeta) must match.

An inner_delta may be specified to subtract the halo at that bias from the result.

AbstractComponents may define their own halo methods.

source
DeviceLayout.parametersFunction
parameters(comp::AbstractComponent)

The component's NamedTuple of parameters.

source
parameters(cc::BasicCompositeComponent)

Retrieve the parameters set indirectly by cc's internal SchematicGraph:

  • name: g.name, from which the component's unique name is generated
  • sub_parameters: A tuple of NamedTuples containing the subcomponent parameters in order
source

Components can be created by several methods. In addition to the keyword constructor, the create_component and set_parameters method allow the use of a set of base parameters or a prototype component to effectively provide a new set of defaults. The @component macro can also be used with either a component type or an instance.

DeviceLayout.SchematicDrivenLayout.@componentMacro
@component comp = MyComponent param1=val1 param2=val2 ...
@component comp = MyComponent begin
    param1 = val1
    param2 = val2
    ...
end
@component comp[1:10] = MyComponent begin 
    param1 .= vals1_vec
    param2 = val2
    ...
end
@component comp[1:10, 1:10] = MyComponent begin
    param1 .= vals1_arr
    param2 = val2
    ...
end

Create a Component or vector of components with specified name and parameters.

For a single component, the symbol on the left-hand side is passed as the name of the component. Parameters can be provided like keyword arguments on the same line or in a block (multiple lines enclosed by begin and end).

If the left-hand side is written as comp[1:n], then comp will be an array of n components with names comp1, comp2, ..., comp$n. A parameter can be passed to all instances using the same syntax as for a single component, or each component can be passed its parameter out of a vector of parameters values vals_vec by using broadcast assignment (param .= vals_vec).

Similarly, multidimensional arrays of components can be created using @component comp[1:m, 1:n].

A component instance can also be used in place of the component type, in which case the "default" values for unspecified parameters will be those of that component.

source
DeviceLayout.SchematicDrivenLayout.create_componentFunction
create_component(
    ::Type{T},
    name::String=default_parameters(T).name,
    base_parameters::NamedTuple=default_parameters(T);
    kwargs...
) where {T <: AbstractComponent}

Create an instance of type T with name name and parameters derived by merging kwargs into base_parameters.

The parameter merge is recursive, meaning that a NamedTuple keyword argument will be merged into the corresponding NamedTuple base parameter. This can be convenient because not every "subparameter" within that NamedTuple needs to be specified. This is in contrast to the default component keyword constructor, which does not merge recursively.

source
DeviceLayout.SchematicDrivenLayout.set_parametersFunction
set_parameters(
    c::AbstractComponent,
    name::String=name(c),
    params::NamedTuple=parameters(c);
    kwargs...
)

Create an instance of type typeof(c) with name name and parameters derived by merging kwargs into `params.

The parameter merge is recursive, meaning that a NamedTuple keyword argument will be merged into the corresponding NamedTuple base parameter. This can be convenient because not every "subparameter" within that NamedTuple needs to be specified. This is in contrast to the default component keyword constructor, which does not merge recursively.

This can also be written by calling the component instance c like a function: c(name, params; kwargs...).

source

Built-in components

We provide some other predefined components that may be generally useful.

DeviceLayout.SchematicDrivenLayout.ArrowAnnotationType
struct ArrowAnnotation{T} <: AbstractComponent{T}
    name::String = "arrow"
    length = 0.032mm
    width = 0.005mm
    text::String = ""
    textsize = 0.025mm
    meta = SemanticMeta(:annotation)
end

An arrow with a given length and width along with a text annotation in the layer given by meta.

Hooks

  • nock: The base of the arrow, with inward direction along the arrow
  • tip: The tip of the arrow, with inward direction opposite the arrow
source
DeviceLayout.SchematicDrivenLayout.BasicComponentType
struct BasicComponent{T} <: AbstractComponent{T}
BasicComponent(cs::CoordinateSystem{T}, hooks=(;))

A simple AbstractComponent that acts as a lightweight wrapper for a CoordinateSystem.

The component geometry is a fixed CoordinateSystem, provided to the constructor along with hooks.

source
DeviceLayout.SchematicDrivenLayout.GDSComponentType
struct GDSComponent{T} <: AbstractComponent{T}
    name::String
    cell::Cell{T}
    hooks::NamedTuple
    meta::DeviceLayout.Meta
end

A component with geometry corresponding to an explicit Cell.

The meta field does not affect metadata inside the Cell, but can still be used by a LayoutTarget to decide whether the component should be rendered or not.

Hooks are supplied by the user, with a default of compass().

source
DeviceLayout.SchematicDrivenLayout.SpacerType
Spacer{T} <: AbstractComponent{T}

Provides an 8-point compass of hooks at each of two points separated by p1.

Parameters

  • p1: The endpoint of the spacer

Hooks

  • p0_east: Hook at the origin, with in_direction pointing "east" (positive x direction)
  • p0_northeast
  • p0_north
  • ...
  • p0_southeast
  • p1_east: Hook at p1, with in_direction pointing "east" (positive x direction)
  • p1_northeast
  • ...
  • p1_southeast
source

Paths as components

Another component already showed up in geometry-level layout: DeviceLayout.Path is an AbstractComponent with hooks p0 and p1 corresponding to its start and end. Path supports the interface described above and can be added directly to a schematic just like any other component.

DeviceLayout.hooksMethod
hooks(pa::Path)
  • :p0: A HandedPointHook looking into the start of path pa.
  • :p1: A HandedPointHook looking into the end of path pa.
  • :p0_lh: A left-handed HandedPointHook looking into the start of path pa.
  • :p1_lh: A left-handed HandedPointHook looking into the end of path pa.
source

Recall that Path supports a geometry-level attach! method that can place references to other structures along it. It also supports a schematic-level attach! with a similar syntax, which positions components along the path by defining an edge in the schematic graph.

Composite components

A "composite" component is one that's at least partly made up of other components. Nothing stops you from "baking in" subcomponents in your component's geometry function by deriving parameters and getting geometries for those subcomponents yourself. You could even construct a SchematicGraph then plan, check!, and build! it to get a coordinate system of subcomponents fused together. But in that case, your top-level schematic won't know anything about what's inside your composite component.

As an alternative, we define abstract type AbstractCompositeComponent <: AbstractComponent, which is minimally a Component with a graph(cc::MyCompositeComponent) method that produces a SchematicGraph of the subcomponents it's made from, such that the composite component's geometry is just build!(plan(graph(cc))).

SchematicDrivenLayout provides a concrete composite component: BasicCompositeComponent, which is really just a graph defined by the user and wrapped in a Component. It maps parameters and hook names exposed by the composite component by prefixing their names with _i_, where i is the index of the subcomponent node in graph(cc).

A new subtype of CompositeComponent can be defined to use a custom reparameterization and mapping of hook names in the subgraph.

DeviceLayout.SchematicDrivenLayout.AbstractCompositeComponentType
abstract type AbstractCompositeComponent{T} <: AbstractComponent{T}

A Component with geometry derived from that of a SchematicGraph of subcomponents.

The alias CompositeComponent = AbstractCompositeComponent{typeof(1.0nm)} is provided for convenience.

A standard Component c is described by its geometry(c), parameters(c), and hooks(c). In contrast, a CompositeComponent cc also has parameters, but is otherwise described at the level of graph(cc) and map_hooks(cc), which define a relationship between the CompositeComponent and the geometry and hooks of its subcomponents.

If a SchematicGraph g contains a node with a CompositeComponent, then the subgraph graph(cc) will be accessible to inspection tools for g. For example, find_components can return nodes in the subgraph. You can also flatten!(g) to simply replace cc's node with graph(cc).

The list of subcomponents in the graph can be obtained with components(cc) (equivalent to components(graph(cc))).

In order to take advantage of this interface, the implementation of a CompositeComponent should contain the following fields, in order:

  • parameters::NamedTuple: A collection of parameters

A CompositeComponent must also implement the following specializations:

  • _build_subcomponents: Returns a Tuple of subcomponents
  • _graph!(g::SchematicGraph, cc::MyComponent, subcomps::NamedTuple): Populates and connects the schematic graph corresponding to cc, where subcomps contains the results of _build_subcomponents keyed by name
  • map_hooks(::Type{MyComponent}): A Dict{Pair{Int, Symbol}, Symbol mapping subcomponent hooks to hooks presented by the composite component.

Validation or reconciling of parameters should be done in an inner constructor that replaces the default inner constructor.

If you define your own abstract composite component subtype you should define SchematicDrivenLayout.iscomposite(::Val{:MyAbstractCompositeComponent}) = true to allow the @compdef macro to recognize that the component is composite.

source
DeviceLayout.SchematicDrivenLayout.CompositeComponentType
const CompositeComponent = AbstractCompositeComponent{typeof(1.0UPREFERRED)}

CompositeComponent is an alias for AbstractCompositeComponent with the coordinate type typeof(1.0UPREFERRED).

DeviceLayout.UPREFERRED is a constant set according to the unit preference in Project.toml or LocalPreferences.toml. The default ("PreferNanometers") gives const UPREFERRED = DeviceLayout.nm, with mixed-unit operations preferring conversion to nm.

source
DeviceLayout.SchematicDrivenLayout.BasicCompositeComponentType
struct BasicCompositeComponent{T} <: AbstractCompositeComponent{T}

A simple AbstractCompositeComponent that acts as a lightweight wrapper for a SchematicGraph.

The component scc = BasicCompositeComponent(g::SchematicGraph) copies g and generates its geometry as build!(check!(plan(g))).

hooks(scc) returns a NamedTuple with the hook h of the ith subcomponent as _i_h.

Parameters are set indirectly by the internal SchematicGraph:

  • name: g.name, from which the component's unique name is generated
  • sub_parameters: A tuple of NamedTuples containing the subcomponent parameters in order

A BasicCompositeComponent instance can also be used as a constructor, taking the argument param_sets (a tuple of parameters for each subcomponent, in order), along with keyword arguments _i_param for a parameter named param in subcomponent i. Default values are provided by the components in g.

    (cc::BasicCompositeComponent)(
        param_sets::Tuple = ();
        kwargs...)

Create a version of cc with different subcomponent parameters.

Argument param_sets is a tuple of NamedTuples containing each subcomponent's parameters. If it is not empty, it must have a NamedTuples for each subcomponent, even an empty one.

Keyword arguments are _i_param for a parameter named param in subcomponent i. Default values are provided by the components in g.

source
DeviceLayout.SchematicDrivenLayout.componentsMethod
components(cc::AbstractCompositeComponent)

A list of the components in the subgraph of cc. Equivalent to components(graph(cc))

Unlike subcomponents, components will return a component for every node, even if multiple nodes use the same component.

source
DeviceLayout.flattenMethod
flatten(g::SchematicGraph; depth=-1)

Create a copy of g with all AbstractCompositeComponents replaced by their graphs.

For non-composite components, the identical ComponentNodes will be preserved.

Keywords

  • depth: How many times to iteratively flatten top-level AbstractCompositeComponents. If negative, will repeat until no AbstractCompositeComponents remain.
source
DeviceLayout.SchematicDrivenLayout.map_hooksFunction
map_hooks(cc::AbstractCompositeComponent)
map_hooks(cc::Type{<:AbstractCompositeComponent})

A Dict{Pair{Int, Symbol}, Symbol} mapping subcomponent hooks to composite hooks.

For example, the entry (2 => :readout) => :readout_2 means the readout hook for the subcomponent in graph(cc)'s node 2 will be available as hooks(cc).readout_2 in the composite geometry.

Subcomponent Hooks that are not mapped will still be available as :_$(i)_$h, where i is the subcomponent's node index in graph(cc) and h is the hook name. In other words, the above example would have the fallback default :_2_readout.

source

Modifying components

Sometimes we want to use components in ways the component designer didn't predict. For example, we might want to draw a Qubit component on the top chip in a flipchip assembly, but the metadata in the generated geometry corresponds to the bottom chip.

There are a couple ways to do this concisely. One is to take a Qubit and run map_metadata! on it:

q = Qubit()
map_metadata!(q, facing)

This applies facing to each piece of metadata in geometry(q). Any function of metadata that returns metadata can be used as the second argument, so if you only wanted to flip the :jj layer, you could write map_metadata!(q, m -> layer(m) == :jj ? facing(m) : m).

Note that geometry(q) is associated only with q, and changes to it are not tracked elsewhere. If, in a later step, you were to apply junction width corrections by replacing q with q2 = typeof(q)(; parameters(q)..., jj_width=new_width), then q2 would not be on the flip chip.

For larger changes, we can make a new Component type. Rather than copy the Qubit definition and find-and-replace its metadata, we can use the @variant macro.

@variant FlipchipQubit Qubit map_meta = facing
fq = FlipchipQubit()
all(level.(element_metadata(geometry(fq))) .== 2)

This creates a new type, FlipchipQubit, and automatically defines the required methods for Component implementation using the Qubit implementation. It has the same default_parameters, hooks, and almost the same _geometry!. Since we supplied the optional keyword map_meta, the geometry method for the new type creates a Qubit and then applies facing to each element (and referenced structure, recursively), as in the map_metadata! example above. But unlike with using map_metadata! on a single Qubit instance, you can replace fq with another typeof(fq) without losing the level information.

You can also go further with manual modifications. You could add a cutout on the bottom chip, along with a parameter to control the size of the cutout:

@variant CutoutFlipchipQubit Qubit map_meta = facing new_defaults = (; cutout_margin=20μm)
function SchematicDrivenLayout._geometry!(cs::CoordinateSystem, fq::CutoutFlipchipQubit)
    _geometry!(cs, base_variant(fq)) # base_variant gives you the equivalent `Qubit`
    map_metadata!(cs, facing)
    # The above lines are what we would get from @variant Qubit map_meta=facing
    # Below, we add a cutout on the bottom chip
    return place!(cs, offset(bounds(cs), parameters(fq).cutout_margin)[1], BASE_NEGATIVE)
end

Note that if Qubit were a CompositeComponent, we would have to use the macro @composite_variant instead.

DeviceLayout.SchematicDrivenLayout.base_variantFunction
base_variant(comp::AbstractComponent)

If comp is a @variant of some other component type T <: AbstractComponent, return an instance of T with the same name as comp; otherwise, return comp.

When the base component shares a parameter with comp, then in the returned component, that parameter will take the value it has in comp.

source
base_variant(comptype::Type{<:AbstractComponent})

If comptype is a @variant of some other component type T <: AbstractComponent, return T; otherwise, return comptype.

source
DeviceLayout.SchematicDrivenLayout.@variantMacro
@variant NewType BaseType new_defaults=(;) map_meta=nothing

Create NewType <: AbstractComponent based on BaseType, with optional new_defaults and map_meta.

Default parameters for the new type will be new_defaults merged into default_parameters(T). You can override the original defaults or add entirely new parameters this way.

If provided, map_meta should be a function of DeviceLayout.Meta that returns another DeviceLayout.Meta. It will be applied recursively to the geometry of the base component using map_metadata!.

Individual methods like hooks and _geometry! can then be overridden to create variant behavior.

source
DeviceLayout.SchematicDrivenLayout.@composite_variantMacro
@composite_variant NewType BaseType new_defaults=(;) map_meta=nothing

Create NewType <: AbstractCompositeComponent based on BaseType, with optional new_defaults and map_meta.

Default parameters for the new type will be new_defaults merged into default_parameters(T).

If provided, map_meta should be a function of DeviceLayout.Meta that returns another DeviceLayout.Meta. It will be applied recursively to the geometry of the base component using map_metadata!.

Individual methods like hooks and _geometry! can then be overridden to create variant behavior.

source