Component Parameters

Components are represented by the ModelDef class. The model definition has a name (often the name of the Cell) and holds parameter definitions (ModelParam) and callbacks (ModelCbBase), whose types are defined in ModelCbType.

When defining a parameter for your component, create a ModelParam, which represents the definition of your parameter. The ModelParam has a name, a label for display within ADS, an optional ModelUnitType, an optional ModelParamType, and the Forms (held in a Formset) that describe how the parameter is displayed and netlisted. After instantiating a ModelParam, you will typically want to provide a default value (ParamItem) and/or callbacks (ModelCbBase) for the parameter. All the parameter definitions for your component will then need to be added to the model definition by calling append_parameter or insert_parameter.

When you are satisfied with the definition of your component, add it to a Library by calling add_model_definition.

In summary, default parameter values and callbacks are added to a parameter definition, parameter definitions are added to a model definition, and the model definition is added to a library. The components represented by the model definition can then be placed in a design.

ADS will automatically attempt to create the definition of your component when a Cell is first accessed by executing the well-known function create_itemdef inside the well-known file called itemdef.py located in the directory of your Cell

See Enabling Python Support For Your Library for more information on initialization of Python enabled libraries.

# itemdef.py is imported by ADS when the cell is first accessed and ADS will attempt to call the function create_itemdef
def create_itemdef(cell: de.Cell) -> None:
    def creating_a_string_parameter(cell: de.Cell) -> None:
        # Create the parameter definition using the StdFormSet formset provided by ADS.
        formset = de.db.model_lib.formsets["StdFormSet"]
        string_param = de.db.ModelParam("string", "String", formset, de.db.ModelUnitType.NO_UNIT)
        # Set the default value of the parameter to "Hello, World!"
        string_param.default_value = de.db.ParamItemString("", "StdForm", "Hello, World!")
        # Create the model definition representing the component
        model_def = de.db.ModelDef(cell.name, cell.name)
        # Placed component names will be X1, X2, etc.
        model_def.inst_name_prefix = "X"
        model_def.is_sub_design = False
        # Add the parameter definition to the model definition
        model_def.parameters = string_param
        # And add the model definition to the library
        de.add_model_definition(cell.library, model_def)

    creating_a_string_parameter(cell)

When an Instance of your component has been placed in a Design, you can access the parameters via the parameters property of the Instance. The parameters attached to an Instance are of type ParamBase and provide accessors to the parameter’s value (ParamItem) and definition (ModelParam)

Example illustrating how to create and modify a repeated parameter.

def creating_a_repeated_parameter(cell: de.Cell) -> None:
    formset = de.db.model_lib.formsets["StdFormSet"]
    # You can use the make_string_param function to create a string parameter value
    if True:
        default_repeats = [
            de.db.std_string_param("0"),
            de.db.std_string_param("2"),
        ]
    # Or call the ParamItemString constructor directly
    else:
        default_repeats = [
            de.db.ParamItemString("", "StdForm", "0"),
            de.db.ParamItemString("", "StdForm", "2"),
        ]
    # Create a repeated parameter value using a list of values
    # Like make_string_param, you can use repeated_param to create a repeated parameter value
    if True:
        default_repeated_param = de.db.repeated_param(default_repeats)
    # Or call the ParamItemRepeated constructor directly
    else:
        default_repeated_param = de.db.ParamItemRepeated("", default_repeats)
    # Append a repeated parameter value to the end (using either append or +=)
    if True:
        default_repeated_param.repeats.append(de.db.std_string_param("3"))
    else:
        default_repeated_param.repeats += de.db.std_string_param("3")

    # Insert a repeated value at the specified index
    default_repeated_param.repeats.insert(1, de.db.std_string_param("1"))

    repeats = default_repeated_param.repeats
    assert [de.db.ParamItem.is_string(repeat) and repeat.value for repeat in repeats] == ["0", "1", "2", "3"]

    # Remove the repeat at the specified index
    extracted_repeat = default_repeated_param.repeats.pop(2)
    assert de.db.ParamItem.is_string(extracted_repeat) and extracted_repeat.value == "2"

    # Verify it has been removed
    repeats = default_repeated_param.repeats
    assert [de.db.ParamItem.is_string(repeat) and repeat.value for repeat in repeats] == ["0", "1", "3"]

    # Clear the repeated values and set new repeated values.
    default_repeated_param.repeats = default_repeats

    repeats = default_repeated_param.repeats
    assert [de.db.ParamItem.is_string(repeat) and repeat.value for repeat in repeats] == ["0", "2"]

    repeated_param = de.db.ModelParam("repeat", "Repeat", formset, de.db.ModelUnitType.NO_UNIT)
    repeated_param.is_repeated = True
    repeated_param.default_value = default_repeated_param

    model_def = de.db.ModelDef(cell.name, cell.name)
    model_def.inst_name_prefix = "X"
    model_def.is_sub_design = False
    model_def.parameters = repeated_param
    de.add_model_definition(cell.library, model_def)

Example illustrating how to create a repeated compound parameter.

def creating_a_repeated_compound_parameter(cell: de.Cell, design: db_uu.Design) -> None:
    # Create the form for the compound parameter
    def create_compound_form(library: de.Library) -> de.db.CompoundForm:
        formset = de.db.model_lib.formsets["StdFormSet"]
        parm_first = de.db.ModelParam("first", "x val", formset, de.db.ModelUnitType.NO_UNIT)
        parm_second = de.db.ModelParam("second", "y val", formset, de.db.ModelUnitType.NO_UNIT)
        parm_third = de.db.ModelParam("third", "z val", formset, de.db.ModelUnitType.NO_UNIT)
        params = [parm_first, parm_second, parm_third]
        # See 'Creating New Component Definitions' in ADS documentation for percent string syntax.
        compound_form = de.db.CompoundForm("CompoundForm", "x,y,z", params, display_format="(%0s,%1s,%2s)")
        library.forms.add(compound_form)
        return compound_form

    compound_form = create_compound_form(cell.library)
    compound_formset = de.db.Formset("CompoundForm", [compound_form])
    cell.library.formsets.add(compound_formset)

    # We'll have a repeated parameter where each parameter repeat is a compound parameter
    default_compound_value_1 = [
        de.db.ParamItemString("X", "StdForm", "1"),
        de.db.ParamItemString("Y", "StdForm", "2"),
        de.db.ParamItemString("Z", "StdForm", "3"),
    ]

    default_compound_value_2 = [
        de.db.ParamItemString("X", "StdForm", "10"),
        de.db.ParamItemString("Y", "StdForm", "20"),
        de.db.ParamItemString("Z", "StdForm", "30"),
    ]
    # Default value, a repeated parameter with two compound parameter values
    default_compound_param_value_1 = de.db.compound_param("StdForm", default_compound_value_1)
    default_compound_param_value_2 = de.db.compound_param("StdForm", default_compound_value_2)
    default_param_value = de.db.repeated_param([default_compound_param_value_1, default_compound_param_value_2])

    repeated_compound_param = de.db.ModelParam(
        "repeat_compound", "Repeat Compound", compound_formset, de.db.ModelUnitType.NO_UNIT
    )

    repeated_compound_param.is_repeated = True
    repeated_compound_param.default_value = default_param_value

    repeats = default_param_value.repeats
    repeat_0 = repeats[0]
    repeat_1 = repeats[1]
    assert de.db.ParamItem.is_compound(repeat_0) and len(repeat_0.sub_params) == 3
    assert de.db.ParamItem.is_compound(repeat_1) and len(repeat_1.sub_params) == 3
    assert [de.db.ParamItem.is_string(param) and param.value for param in repeat_0.sub_params] == ["1", "2", "3"]
    assert [de.db.ParamItem.is_string(param) and param.value for param in repeat_1.sub_params] == ["10", "20", "30"]

    model_def = de.db.ModelDef(cell.name, cell.name)
    model_def.inst_name_prefix = "X"
    model_def.is_sub_design = False
    model_def.parameters = repeated_compound_param
    de.add_model_definition(cell.library, model_def)

    # Place an instance of the component into a design and validate the default parameter values
    def place_instance_and_validate_default_parameter_values(design: db_uu.Design) -> None:
        assert design.is_layout
        design.clear_design()
        inst = design.add_instance(db_uu.LCVName(design.library, cell, None), (0, 0))
        # The parameter is a repeated parameter with the repeats being compound parameters
        repeat_compund_param = inst.parameters["repeat_compound"]
        assert de.db.ParamBase.is_repeated(repeat_compund_param)

        repeats = repeat_compund_param.repeats
        # Verify first repeat
        compound_0 = repeats[0]
        assert de.db.ParamBase.is_compound(compound_0)
        assert de.db.ParamBase.is_string(compound_0.sub_params[0])
        assert de.db.ParamBase.is_string(compound_0.sub_params[1])
        assert de.db.ParamBase.is_string(compound_0.sub_params[2])
        assert compound_0.sub_params[0].value == "1"
        assert compound_0.sub_params[1].value == "2"
        assert compound_0.sub_params[2].value == "3"

        # Verify second repeat
        compound_1 = repeats[1]
        assert de.db.ParamBase.is_compound(compound_1)
        sub_params_1 = compound_1.sub_params
        assert all(de.db.ParamBase.is_string(sub_param) for sub_param in sub_params_1)
        assert [sub_param.value for sub_param in sub_params_1] == ["10", "20", "30"]
        design.save_design()

    place_instance_and_validate_default_parameter_values(design)

Example illustrating how to append and remove repeats to and from a repeated parameter.

def appending_and_removing_repeats_to_a_repeated_parameter(cell: de.Cell, design: db_uu.Design) -> None:
    # create_itemdef below is a bit of setup for creating a model definition that has a parameter
    # that represents the vertices of a shape.
    # It consists of a repeated parameter where each repeat is a compound parameter, made up
    # of two string parameters representing the x and y coordinates.
    # [shape]                  repeat
    # [point]           compound    compound     ...
    # [x,y]     string,  string      string,   string    ..., ...

    def create_itemdef(cell: de.Cell) -> None:
        def create_point_form(lib: de.Library) -> de.db.CompoundForm:
            formset = de.db.model_lib.formsets["StdFormSet"]
            parm_first = de.db.ModelParam("first", "x coordinate", formset, de.db.ModelUnitType.LENGTH)
            parm_second = de.db.ModelParam("second", "y coordinate", formset, de.db.ModelUnitType.LENGTH)
            params = [parm_first, parm_second]
            point_form = de.db.CompoundForm("PointForm", "x,y", params, display_format="(%0s,%1s)")
            lib.forms.add(point_form)
            return point_form

        library = cell.library
        point_form = create_point_form(library)
        point_formset = de.db.Formset("PointForms", [point_form])
        library.formsets.add(point_formset)
        # Setting up an initial point at 0.0, 0.0
        initial_point = de.db.compound_param(
            "PointForm", [de.db.std_string_param("0.0 mil"), de.db.std_string_param("0.0 mil")]
        )
        param_vertices = de.db.ModelParam("vertices", "vertex coordinates", point_formset, de.db.ModelUnitType.NO_UNIT)
        param_vertices.default_value = de.db.repeated_param([initial_point])
        # Vertices is a repeated parameter
        param_vertices.is_repeated = True
        shape = de.db.ModelDef(cell.name, cell.name)
        shape.inst_name_prefix = "X"
        shape.is_sub_design = False
        shape.parameters = param_vertices
        de.add_model_definition(library, shape)

    create_itemdef(cell)

    # Place an instance of the component and work with the vertices parameter
    inst = design.add_instance(db_uu.LCVName(cell.library, cell, None), (0, 0))
    param = inst.parameters["vertices"]

    assert de.db.ParamBase.is_repeated(param)
    assert len(param.repeats) == 1
    compound_0 = param.repeats[0]
    assert de.db.Param.is_compound(compound_0)
    assert compound_0.sub_params[0].value == "0.0 mil"
    assert compound_0.sub_params[1].value == "0.0 mil"

    # Additional repeats can be added in a variety of ways:
    # You can clone a repeat at the specified index and modify its values.
    param.repeats.clone(0)
    assert len(param.repeats) == 2
    compound_1 = param.repeats[1]
    assert de.db.Param.is_compound(compound_1)
    # Verify the cloned repeat has the same values as the original
    assert compound_1.sub_params[0].value == "0.0 mil"
    assert compound_1.sub_params[1].value == "0.0 mil"
    # And update the values
    compound_1.sub_params[0].value = "10.0 mil"
    compound_1.sub_params[1].value = "0.0 mil"
    # You can call append to append a new repeat
    next_point = de.db.compound_param(
        "PointForm", [de.db.std_string_param("10.0 mil"), de.db.std_string_param("10.0 mil")]
    )
    param.repeats.append(next_point)
    assert len(param.repeats) == 3
    compound_2 = param.repeats[2]
    assert de.db.Param.is_compound(compound_2)
    assert compound_2.sub_params[0].value == "10.0 mil"
    assert compound_2.sub_params[1].value == "10.0 mil"

    next_point = de.db.compound_param(
        "PointForm", [de.db.std_string_param("0.0 mil"), de.db.std_string_param("10.0 mil")]
    )
    # You can also use the += operator to append a new repeat
    param.repeats += next_point
    assert len(param.repeats) == 4
    compound_3 = param.repeats[3]
    assert de.db.Param.is_compound(compound_3)
    assert compound_3.sub_params[0].value == "0.0 mil"
    assert compound_3.sub_params[1].value == "10.0 mil"

    # New repeats may also be inserted at a specified index
    new_point = de.db.compound_param(
        "PointForm", [de.db.std_string_param("5.0 mil"), de.db.std_string_param("15.0 mil")]
    )
    param.repeats.insert(3, new_point)
    assert len(param.repeats) == 5
    compound_3 = param.repeats[3]
    assert de.db.Param.is_compound(compound_3)
    assert compound_3.sub_params[0].value == "5.0 mil"
    assert compound_3.sub_params[1].value == "15.0 mil"
    compound_4 = param.repeats[4]
    assert de.db.Param.is_compound(compound_4)
    assert compound_4.sub_params[0].value == "0.0 mil"
    assert compound_4.sub_params[1].value == "10.0 mil"

    # You can remove a repeat at the specified index a couple of different ways
    # remove will simply remove the repeat at the specified index
    param.repeats.remove(3)
    assert len(param.repeats) == 4
    compound_3 = param.repeats[3]
    assert de.db.Param.is_compound(compound_4)
    assert compound_4.sub_params[0].value == "0.0 mil"
    assert compound_4.sub_params[1].value == "10.0 mil"

    # whereas pop will remove the item and return it
    removed = param.repeats.pop(-1)
    assert de.db.Param.is_compound(removed)
    assert removed.sub_params[0].value == "0.0 mil"
    assert removed.sub_params[1].value == "10.0 mil"
    assert len(param.repeats) == 3
    compound_2 = param.repeats[2]
    assert de.db.Param.is_compound(compound_2)
    assert compound_2.sub_params[0].value == "10.0 mil"
    assert compound_2.sub_params[1].value == "10.0 mil"

Example illustrating how to create a Formset with constant Forms and a parameter using the Formset

def creating_and_using_a_constant_form(cell: de.Cell, design: db_uu.Design) -> None:
    library = cell.library
    # Create yes/no forms and formset and add them to the library
    # We want these forms to be netlisted as "yes" and "no"
    yes_form = de.db.ConstForm("Yes", "YES", "yes")
    no_form = de.db.ConstForm("No", "NO", "no")
    library.forms.add(yes_form)
    library.forms.add(no_form)
    yes_no_formset = de.db.Formset("Yes/No", [yes_form, no_form])
    library.formsets.add(yes_no_formset)

    # Create a parameter with the yes/no formset and a default value of yes
    decision_param = de.db.ModelParam("decision", "Yes or No", yes_no_formset)
    assert "real" == decision_param.param_type.value
    assert decision_param.unit_type == de.db.ModelUnitType.NO_UNIT
    decision_param.default_value = de.db.const_param("Yes")

    # Add the model definition to the library
    model_def = de.db.ModelDef(cell.name, cell.name)
    model_def.inst_name_prefix = "X"
    model_def.is_sub_design = False
    model_def.parameters = decision_param
    de.add_model_definition(library, model_def)

    # Place an instance and modify the constant form parameter value
    def place_instance_and_validate_parameter_values(design: db_uu.Design) -> None:
        assert design.is_layout
        design.clear_design()
        inst = design.add_instance(db_uu.LCVName(design.library, cell, None), (0, 0))
        # The parameter is a repeated parameter with the repeats being compound parameters
        decision_parameter = inst.parameters["decision"]
        assert de.db.ParamBase.is_const(decision_parameter)
        # ConstForm parameter values are the netlisted value (net_format)
        assert decision_parameter.value == "yes"
        # Assignment of a value to a parameter will attempt to find a matching form.
        # This matching will look at name, label, net_format and display_format for ConstForm.
        decision_parameter.value = "NO"
        ael.call.de_edit_inst_param_value(inst, "decision", "No", "NO", (0, 0))
        assert design.instances["X1"].parameters["decision"].value == "no"

        decision_parameter = design.instances["X1"].parameters["decision"]
        # Setting to an invalid value will revert to the default value
        decision_parameter.value = "Not Valid"
        assert decision_parameter.value == "yes"

        decision_parameter.value = "NO"
        assert decision_parameter.value == "no"

        # Setting to an invalid value will revert to the default value
        ael.call.de_edit_inst_param_value(inst, "decision", "No", "Not Valid", (0, 0))
        assert design.instances["X1"].parameters["decision"].value == "yes"

        design.save_design()

    place_instance_and_validate_parameter_values(design)

Example illustrating how to evaluate the value of a parameter.

def evaluating_a_parameter(cell: de.Cell, design: db_uu.Design) -> None:
    # Item definition with a couple length values in different units
    def create_itemdef(cell: de.Cell) -> None:
        formset = de.db.model_lib.formsets["StdFormSet"]
        # Length parameter in mils
        length_param_in_mils = de.db.ModelParam("l_in_mils", "L in mils", formset, de.db.ModelUnitType.LENGTH)
        length_param_in_mils.default_value = de.db.ParamItemString("", "StdForm", "25 mil")

        # Length parameter in microns
        length_param_in_microns = de.db.ModelParam("l_in_microns", "L in microns", formset, de.db.ModelUnitType.LENGTH)
        length_param_in_microns.default_value = de.db.ParamItemString("", "StdForm", "25 um")

        # Length parameter with an expression
        length_with_expr = de.db.ModelParam("l_with_expr", "L with expr", formset, de.db.ModelUnitType.LENGTH)
        length_with_expr.default_value = de.db.ParamItemString("", "StdForm", "10 * 25 mil")

        model_def = de.db.ModelDef(cell.name, cell.name)
        model_def.inst_name_prefix = "X"
        model_def.is_sub_design = False
        model_def.parameters = [length_param_in_mils, length_param_in_microns, length_with_expr]
        de.add_model_definition(cell.library, model_def)

    def place_instance_and_evaluate_parameter_value(design: db_uu.Design) -> None:
        assert design.is_layout
        design.clear_design()
        inst = design.add_instance(db_uu.LCVName(design.library, cell, None), (0, 0))

        l_in_mils = inst.parameters["l_in_mils"]
        assert de.db.ParamBase.is_string(l_in_mils)
        # Value before evaluation
        assert l_in_mils.value == "25 mil"

        l_in_ums = inst.parameters["l_in_microns"]
        assert de.db.ParamBase.is_string(l_in_ums)
        # Value before evaluation
        assert l_in_ums.value == "25 um"

        # Evaluating a parameter with a LENGTH ModelUnitType returns the value in meters
        val_in_meters = float(l_in_mils.evaluate_no_expr())
        assert val_in_meters == 0.000635  # 25 mil * 2.54e-5 m/mil == 0.000635 m
        val_in_meters = float(l_in_ums.evaluate_no_expr())
        assert val_in_meters == 0.000025  # 25 um * 1e-6 um/m == 0.000025 m

        l_with_expr = inst.parameters["l_with_expr"]
        assert de.db.ParamBase.is_string(l_with_expr)
        assert l_with_expr.value == "10 * 25 mil"

        # Cannot call evaluate_no_expr on a parameter with an expression
        try:
            l_with_expr.evaluate_no_expr()
        except RuntimeError as e:
            assert (
                str(e)
                == 'Error processing the value for parameter "l_with_expr": Could not evaluate value without simulation'
            )
            expr_context = de.db.ExpressionContext()
            expr_context.setup_hierarchy_for_design(design)
            expr_val_in_meters = l_with_expr.evaluate(expr_context)
            assert isinstance(expr_val_in_meters, float)

        import math

        assert math.isclose(expr_val_in_meters, 0.00635, rel_tol=1e-6)  # 10 * 25 mil == 25 * 10 * 2.54e-5 == 0.00635

    create_itemdef(cell)
    place_instance_and_evaluate_parameter_value(design)

Example illustrating how to add a callback to an existing ADS component.

def adding_a_callback_to_existing_component(design: db_uu.Design) -> None:
    # Open the design of an ADS component
    snp_design = db_uu.open_design("ads_datacmps:SnP:symbol", de.db.DesignMode.READ_ONLY)
    # Create an item info object to obtain the model definition of the SnP component
    if True:
        item_info = de.ItemInfo(design, de.LCVName("ads_datacmps", "SnP", "symbol"), de.ItemEditMode.TEMP)
        model_def = item_info.model_def
    # Model definition can be retrieved in more than one way
    else:
        model_def = de.db.ModelDef.find_model_def(snp_design.library, "SnP")

    assert model_def is not None
    # ModelParam of the NumPorts parameter
    num_ports_model_param = model_def.parameters.get("NumPorts")
    # Default number of ports is 1
    def_num_ports_value = num_ports_model_param.get_default_value_copy(snp_design, model_def)
    assert def_num_ports_value and de.db.ParamItem.is_string(def_num_ports_value) and def_num_ports_value.value == "1"
    # Starting fresh, just in case
    design.clear_design()
    # Add the SnP component to the design
    inst_1_port = design.add_instance(("ads_datacmps", "SnP", "symbol"), (0, 0), name="SnP_1Port")
    assert inst_1_port.parameters["NumPorts"].value == "1"

    # Default value callback for the NumPorts parameter
    def snp_num_ports_default_value(
        param: de.db.ModelParam, model_def: de.db.ModelDefBase, design: db_uu.Design
    ) -> de.db.ParamItemString:
        assert param.name == "NumPorts"
        assert model_def.name == "SnP"
        return de.db.std_string_param("8")

    default_num_ports_value_callback = de.db.ModelCb(
        de.db.ModelCbType.PARAMETER_DEFAULT_VALUE,
        snp_num_ports_default_value,
    )
    # Add the callback to the NumPorts ModelParam
    num_ports_model_param.callbacks = default_num_ports_value_callback
    # Add another instance of SnP and validate the default value for NumPorts is now 8
    inst_8_port = design.add_instance(("ads_datacmps", "SnP", "symbol"), (2, 0), name="SnP_8Port")
    assert inst_8_port.parameters["NumPorts"].value == "8"
    # Don't forget to save
    design.save_design()

Example illustrating how to add a callback to an existing component instance placed in a design

def adding_a_callback_to_a_placed_component_instance(design: db_uu.Design) -> None:
    design.clear_design()
    # Set up the design with a resistor
    design.add_instance(("ads_rflib", "R", "symbol"), (0, 0), name="R1")

    inst_r1 = design.instances["R1"]

    assert inst_r1.parameters["Width"].value == ""
    assert inst_r1.parameters["Length"].value == ""

    model_def = inst_r1.model_def
    assert model_def

    def width_modified_callback(item_info: de.ItemInfo, param_name: str) -> bool:
        inst = item_info.instance
        assert inst
        assert param_name == "Width"
        assert inst.name == "R1"
        assert inst.parameters["Width"].value == "10"
        dependent_parm_data = ael.call.pcb_set_mks(None, "Length", 25)
        ael.call.pcb_store_parm_callback_data(item_info, dependent_parm_data)
        return True

    # Add a parameter modified callback for the Width parameter
    width_model_param = model_def.parameters.get("Width")
    modified_width_cb = de.db.ModelCb(
        de.db.ModelCbType.PARAMETER_MODIFIED, lambda item_info: width_modified_callback(item_info, "Width")
    )
    width_model_param.callbacks = modified_width_cb

    ael.call.de_edit_inst_param_value(inst_r1, "Width", "StdForm", "10", (0, 0))
    design.save_design()

Example illustrating how to access the default value of one parameter from the default value callback of another parameter.

def accessing_default_value_of_parameter_from_different_parameter_callback(cell: de.Cell) -> None:
    formset = de.db.model_lib.formsets["StdFormSet"]
    # Length parameter with a default value of 25
    length_param = de.db.ModelParam("length", "Length", formset, de.db.ModelUnitType.NO_UNIT, de.db.ModelParamType.INT)
    length_param.default_value = de.db.std_string_param("25")

    # Width parameter with a default value of 4
    width_param = de.db.ModelParam("width", "Width", formset, de.db.ModelUnitType.NO_UNIT, de.db.ModelParamType.INT)
    width_param.default_value = de.db.std_string_param("4")

    # Area parameter whose value will be computed in its default value callback based on the default
    # values of length and width
    area_param = de.db.ModelParam("area", "Area", formset, de.db.ModelUnitType.NO_UNIT, de.db.ModelParamType.INT)

    # Default value callback for the area parameter. It uses the default values of the
    # width and length parameters to compute the area.
    def calculate_default_area_value(
        param: de.db.ModelParam, model_def: de.db.ModelDefBase, design: db_uu.Design
    ) -> de.db.ParamItemString:
        # Ensure that the callback is being called for the area parameter
        assert param.name == "area"

        # Validate that the default values of the length and width parameters are being used
        length_param = model_def.parameters.get("length")
        default_length_param = length_param.get_default_value_copy(design, model_def)
        assert default_length_param and de.db.ParamItem.is_string(default_length_param)
        length_val = int(default_length_param.value)
        assert length_val == 25

        width_param = model_def.parameters.get("width")
        default_width_param = width_param.get_default_value_copy(design, model_def)
        assert default_width_param and de.db.ParamItem.is_string(default_width_param)
        width_val = int(default_width_param.value)
        assert width_val == 4

        # Calculate the area using the default values of the length and width parameters
        area = length_val * width_val
        return de.db.std_string_param(str(area))

    default_area_value_callback = de.db.ModelCb(
        de.db.ModelCbType.PARAMETER_DEFAULT_VALUE,
        calculate_default_area_value,
    )

    area_param.callbacks = default_area_value_callback

    model_def = de.db.ModelDef(cell.name, cell.name)
    model_def.inst_name_prefix = "X"
    model_def.is_sub_design = False
    model_def.parameters = [length_param, width_param, area_param]
    de.add_model_definition(cell.library, model_def)
On this page